/* 
 * Copyright (c)2009-2025 DemiVision, LLC. All Rights Reserved. The information 
 * herein is the CONFIDENTIAL and PROPRIETARY information of DemiVision, LLC. 
 */

using System.Text.Json.Serialization;

namespace iStatVball3;

/*
 * Encapsulates all data for a MaxPreps match including team preamble and all player stats.
 */
public class MP2Match
{
	/* Constants */
    private const string SportValue = "volleyball";

    /* Properties */

    [JsonPropertyName("sport")] public string Sport { get; set; }
    [JsonPropertyName("gender")] public string Gender { get; set; }
    [JsonPropertyName("teamlevel")] public string TeamLevel { get; set; }
    [JsonPropertyName("season")] public string Season { get; set; }
    [JsonPropertyName("year")] public string Year { get; set; }

    [JsonPropertyName("schoolid")] public string SchoolId { get; set; }
    [JsonPropertyName("opponentschoolid")] public string OpponentSchoolId { get; set; }

    [JsonPropertyName("gamedate")] public string GameDate { get; set; }
    [JsonPropertyName("time")] public string Time { get; set; }

    [JsonPropertyName("teamscore")] public int TeamScore { get; set; }
    [JsonPropertyName("opponentscore")] public int OpponentScore { get; set; }

    [JsonPropertyName("teamboxscores")] public IList<MP2Score> TeamBoxScores { get; set; }
    [JsonPropertyName("opponentboxscores")] public IList<MP2Score> OpponentBoxScores { get; set; }

    [JsonPropertyName("athletesinfo")] public IList<MP2Athlete> AthletesInfo { get; set; }

    /* Fields */
    [JsonIgnore] private Match matchObj;
    
    [JsonIgnore] private Team team;
    [JsonIgnore] private Organization org;

    [JsonIgnore] private DateTimeOffset date;

    /* Methods */

    // Builds all fields for MaxPreps match object
	public async Task Populate( Match match )
	{
        matchObj = match;

        // Convenience references
        team = match.Season.Team;
        org = team.Organization;
        date = match.MatchTime;

        // Team info
        Sport = SportValue;
        Gender = GetGender();
        TeamLevel = GetTeamLevel();

        // Season info
        Season = GetSeason();
        Year = GetYear();

        // Match info
        SchoolId = org.MaxPreps.SchoolId;
        OpponentSchoolId = match.Opponent.MaxPreps.SchoolId;

        GameDate = GetDate();
        Time = GetTime();

        // Scores
        TeamScore = match.Sets1;
        OpponentScore = match.Sets2;

        TeamBoxScores = GetScores( match );
        OpponentBoxScores = GetScores( match, true );

        // Stats
        AthletesInfo = await GetAthletes();
    }

    // Maps to MaxPreps Gender key for this match
    private string GetGender()
    {
        return team.Gender switch
        {
            "womens" or "girls" => "girls",
            "mens" or "boys" => "boys",

            _ => string.Empty
        };
    }

    // Maps to MaxPreps TeamLevel key for this match
    private string GetTeamLevel()
    {
        return team.Level switch
        {
            "varsity" => "varsity",
            "jv" => "jv",
            "fs" => "freshman",
            "soph" => "freshman",
            "frosh" => "freshman",

            _ => string.Empty
        };
    }

    // Returns MaxPreps season key
    private string GetSeason()
    {
        if ( matchObj.StartTime != null )
        {
            int month = ((DateTimeOffset)matchObj.StartTime).Month;

            return month switch
            {
                // Mar-Jun = Spring
                >= 3 and <= 6 => "spring",
                
                // July-Nov = Fall
                >= 7 and <= 10 => "fall",
                
                // Dec-Feb = Winter
                _ => "winter"
            };
        }

        return string.Empty;
    }

    // Returns MaxPreps school year
    private string GetYear()
    {
        Season season = matchObj.Season;

        int year = season.StartDate.Year;

        // '24'
        int thisYear = (year % 2000);

        // Spring season considered previous year
        if ( GetSeason() == "spring" )
        {
            thisYear -= 1;
        }

        // '25'
        int nextYear = (thisYear + 1);

        // '24-25'
        return $"{thisYear}-{nextYear}";
    }

    // Returns MaxPreps date as '9/21/2024'
    private string GetDate()
    {
        return date.LocalDateTime.ToString( "M/dd/yyyy" );
    }

    // Returns MaxPreps time as '6:40 AM'
    private string GetTime()
    {
        return date.LocalDateTime.ToString( "h:mm tt" );
    }

    // Returns list of set scores for primary team or opponent
    private static List<MP2Score> GetScores( Match match, bool opponent = false )
    {
        int count = match.Sets.Count;

        List<MP2Score> scores = new( count );

        // 'S1':25, 'S2':23, etc
        for ( int set = 0; set < count; set++ )
        {
            string name = $"S{set + 1}";
            int value = opponent ? match.Scores2[ set ] : match.Scores1[ set ];

            MP2Score score = new( name, value );

            scores.Add( score );
        }

        return scores;
    }

    // Calculates MaxPreps stats for all players in match
    private async Task<List<MP2Athlete>> GetAthletes()
    {
        // Configure query
        DataConfig config = new()
        {
            Scope = DataConfig.MatchScope,
            ScopeObject = matchObj,

            Organization = org,
            IsTeam1 = true,

            Team1 = matchObj.Team1,
            Team2 = null,

            Action = null,
            OuterDim = "player",
            InnerDim = null,

            DataSet = DataConfig.SkillsData
        };

        // Aggregate stats within scope
        DataStats stats = await DataFilter.Filter( config );

        // Calculate for each player
        await DataDimension.ProcessDimension( config, stats );

        var metricsList = config.Dimension.Metrics.Values;

        List<MP2Athlete> athletes = new( metricsList.Count );

        // Create export object for each player
        foreach ( DataMetrics metrics in metricsList )
        {
            MP2Athlete athlete = new( metrics );

            athletes.Add( athlete );
        }

        return athletes;
    }
}

//
