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

using Syncfusion.Pdf;
using Syncfusion.Pdf.Graphics;

using DXLib.UI;
using DXLib.Utils;

namespace iStatVball3;

/*
 * Draws preamble lines for a PDF report. The preamble includes text lines specific to the scope of the report (set,
 * match, season, career). Lines may include opponent, date, record, etc.
 */
public class PDFPreamble
{
    /* Constants */
    private static readonly PdfColor TextColor = PDFUtils.GetColor( DXColors.Dark1 );

    /* Fields */
    private readonly ExportConfig config;
    private readonly PdfPage page;

    private readonly DataConfig dataConfig;

    /* Methods */
    public PDFPreamble( ExportConfig config, PdfPage page )
    {
        this.config = config;
        this.page = page;

        dataConfig = config.DataConfig;
    }

    // Draws scope specific preamble lines
    public async Task<float> Draw( float y )
    {
        return dataConfig.Scope switch
        {
            DataConfig.SetScope => await DrawSet( y ),
            DataConfig.MatchScope => await DrawMatch( y ),
            DataConfig.TournamentDayScope => await DrawDay( y ),
            DataConfig.TournamentScope => await DrawTournament( y ),
            DataConfig.SeasonScope => await DrawSeason( y ),
            DataConfig.TeamScope => await DrawTeam( y ),
            DataConfig.OrganizationScope => await DrawOrganization( y ),

            _ => y
        };
    }

    /* Scopes */

    // Draws set specific preamble
    private async Task<float> DrawSet( float y )
    {
        if ( dataConfig.ScopeObject is Set set )
        {
            Match match = set.Match;

            // Scope specific formatting
            string team = match.Team1.FullName;
            string record = GetRecord( set.Points1, set.Points2, 0, false );

            DateTimeOffset date = set.StartTime ?? DateTimeOffset.UnixEpoch;

            // Configure filename
            config.Team = team;
            config.Date = date;

            // Configure SendGrid
            config.Line1 = GetTitle();
            config.Line2 = team;
            config.Line3 = GetOpponent( match );
            config.Line4 = GetDate( date );
            config.Line5 = GetSet( set );
            config.Line6 = record;

            const float spacing = PDFUtils.Spacing;
            float y2 = y;

            // Draw preamble
            y2 = await DrawTeam( team, (y2 + (spacing * 4)) );
            y2 = await DrawOpponent( match, (y2 + spacing) );
            y2 = await DrawDate( date, (y2 + spacing) );
            y2 = await DrawSet( set, (y2 + spacing) );
            y2 = await DrawRecord( record, (y2 + spacing) );

            return y2;
        }

        return 0;
    }

    // Draws match specific preamble
    private async Task<float> DrawMatch( float y )
    {
        if ( dataConfig.ScopeObject is Match match )
        {
            Tournament tournament = match.Tournament;

            // Scope specific formatting
            string team = match.Team1.FullName;
            string record = GetRecord( match.Sets1, match.Sets2, 0, false );

            DateTimeOffset date = match.MatchTime;

            // Configure filename
            config.Team = team;
            config.Date = date;

            // Configure SendGrid
            config.Line1 = GetTitle();
            config.Line2 = team;
            config.Line3 = GetOpponent( match );
            config.Line4 = GetTournament( tournament );
            config.Line5 = GetDate( date );
            config.Line6 = record;

            const float spacing = PDFUtils.Spacing;
            float y2 = y;

            // Draw preamble
            y2 = await DrawTeam( team, (y2 + (spacing * 4)) );
            y2 = await DrawOpponent( match, (y2 + spacing) );
            y2 = await DrawTournament( tournament, (y2 + spacing), 8 );
            y2 = await DrawDate( date, (y2 + spacing) );
            y2 = await DrawRecord( record, (y2 + spacing) );

            return y2;
        }

        return 0;
    }

    // Draws tournament day specific preamble
    private async Task<float> DrawDay( float y )
    {
        if ( dataConfig.ScopeObject is TournamentDay day )
        {
            // Scope specific formatting
            string team = dataConfig.Team1.FullName;
            string record = GetRecord( day.Won(), day.Lost(), day.Tied(), true );

            DateTimeOffset date = day.Date;

            // Configure filename
            config.Team = team;
            config.Date = date;

            // Configure SendGrid
            config.Line1 = GetTitle();
            config.Line2 = team;
            config.Line3 = day.FullName;
            config.Line4 = GetDate( date );
            config.Line5 = record;
            config.Line6 = null;

            const float spacing = PDFUtils.Spacing;
            float y2 = y;

            // Draw preamble
            y2 = await DrawTeam( team, (y2 + (spacing * 4)) );
            y2 = await DrawDay( day, (y2 + spacing) );
            y2 = await DrawDate( date, (y2 + spacing) );
            y2 = await DrawRecord( record, (y2 + spacing) );

            return y2;
        }

        return 0;
    }

    // Draws tournament specific preamble
    private async Task<float> DrawTournament( float y )
    {
        if ( dataConfig.ScopeObject is Tournament tournament )
        {
            // Scope specific formatting
            string team = dataConfig.Team1.FullName;
            string record = GetRecord( tournament.Won, tournament.Lost, tournament.Tied, true );

            DateTimeOffset date = tournament.GetDate();

            // Configure filename
            config.Team = team;
            config.Date = date;

            // Configure SendGrid
            config.Line1 = GetTitle();
            config.Line2 = team;
            config.Line3 = GetTournament( tournament );
            config.Line4 = GetDate( date );
            config.Line5 = record;
            config.Line6 = null;

            const float spacing = PDFUtils.Spacing;
            float y2 = y;

            // Draw preamble
            y2 = await DrawTeam( team, (y2 + (spacing * 4)) );
            y2 = await DrawTournament( tournament, (y2 + spacing) );
            y2 = await DrawDate( date, (y2 + spacing) );
            y2 = await DrawRecord( record, (y2 + spacing) );

            return y2;
        }

        return 0;
    }

    // Draws season specific preamble
    private async Task<float> DrawSeason( float y )
    {
        if ( dataConfig.ScopeObject is Season season )
        {
            // Scope specific formatting
            string teamStr = season.Team.FullName;
            string record = GetRecord( season.Won, season.Lost, season.Tied, true );

            DateTimeOffset date = season.StartDate;

            // Configure filename
            config.Team = teamStr;
            config.Date = date;

            // Configure SendGrid
            config.Line1 = GetTitle();
            config.Line2 = teamStr;
            config.Line3 = GetSeason( season );
            config.Line4 = record;
            config.Line5 = null;
            config.Line6 = null;

            const float spacing = PDFUtils.Spacing;
            float y2 = y;

            // Draw preamble
            y2 = await DrawTeam( teamStr, (y2 + (spacing * 4)) );
            y2 = await DrawSeason( season, (y2 + spacing) );
            y2 = await DrawRecord( record, (y2 + spacing) );

            return y2;
        }

        return 0;
    }

    // Draws career (team) specific preamble
    private async Task<float> DrawTeam( float y )
    {
        if ( dataConfig.ScopeObject is Team team )
        {
            string teamStr = team.FullName;

            // Configure filename
            config.Team = teamStr;
            config.Date = DateTimeOffset.Now;

            // Configure SendGrid
            config.Line1 = GetTitle();
            config.Line2 = teamStr;
            config.Line3 = GetCareer();
            config.Line4 = null;
            config.Line5 = null;
            config.Line6 = null;

            const float spacing = PDFUtils.Spacing;
            float y2 = y;

            // Draw preamble
            y2 = await DrawTeam( teamStr, (y2 + (spacing * 4)) );
            y2 = await DrawCareer( (y2 + spacing) );

            return y2;
        }

        return 0;
    }

    // Draws career (org) specific preamble
    private async Task<float> DrawOrganization( float y )
    {
        if ( dataConfig.ScopeObject is Organization org )
        {
            string orgStr = org.Name;

            // Configure filename
            config.Team = orgStr;
            config.Date = DateTimeOffset.Now;

            // Configure SendGrid
            config.Line1 = GetTitle();
            config.Line2 = orgStr;
            config.Line3 = GetCareer();
            config.Line4 = null;
            config.Line5 = null;
            config.Line6 = null;

            const float spacing = PDFUtils.Spacing;
            float y2 = y;

            // Draw preamble
            y2 = await DrawTeam( orgStr, (y2 + (spacing * 4)) );
            y2 = await DrawCareer( (y2 + spacing) );

            return y2;
        }

        return 0;
    }

    /* Draw Lines */

    // Draws scope specific team name to PDF page
    private async Task<float> DrawTeam( string name, float y )
    {
        return await PDFUtils.DrawText( page, name, PDFUtils.BoldFont, 12, TextColor, 0, y );
    }

    // Draws scope specific opponent name to PDF page
    private async Task<float> DrawOpponent( Match match, float y )
    {
        return await PDFUtils.DrawText( page, GetOpponent( match ), PDFUtils.RegularFont, 10, TextColor, 0, y );
    }

    // Draws tournament day name to PDF page
    private async Task<float> DrawDay( TournamentDay day, float y, float size = 10 )
    {
        string dayStr = day.FullName;

        return await PDFUtils.DrawText( page, dayStr, PDFUtils.RegularFont, size, TextColor, 0, y );
    }

    // Draws tournament name to PDF page (if applicable)
    private async Task<float> DrawTournament( Tournament tournament, float y, float size = 10 )
    {
        string tournamentStr = GetTournament( tournament );

        // Tournament optional
        if ( tournamentStr == null )
        {
            return y;
        }

        return await PDFUtils.DrawText( page, tournamentStr, PDFUtils.RegularFont, size, TextColor, 0, y );
    }

    // Draws season name to PDF page
    private async Task<float> DrawSeason( Season season, float y )
    {
        string seasonStr = GetSeason( season );

        return await PDFUtils.DrawText( page, seasonStr, PDFUtils.RegularFont, 10, TextColor, 0, y );
    }

    // Draws career label to PDF page
    private async Task<float> DrawCareer( float y )
    {
        return await PDFUtils.DrawText( page, GetCareer(), PDFUtils.RegularFont, 10, TextColor, 0, y );
    }

    // Draws scope specific date to PDF page
    private async Task<float> DrawDate( DateTimeOffset date, float y )
    {
        return await PDFUtils.DrawText( page, GetDate( date ), PDFUtils.RegularFont, 8, TextColor, 0, y );
    }

    // Draws set number to PDF page
    private async Task<float> DrawSet( Set set, float y )
    {
        return await PDFUtils.DrawText( page, GetSet( set ), PDFUtils.RegularFont, 8, TextColor, 0, y );
    }

    // Draws scope specific record to PDF page
    private async Task<float> DrawRecord( string record, float y )
    {
        return await PDFUtils.DrawText( page, record, PDFUtils.RegularFont, 8, TextColor, 0, y );
    }

    /* Formatting */

    // 'BOX SCORE'
    private string GetTitle()
    {
        return config.Title.ToUpper();
    }

    // 'vs Springfield JV' or 'vs Opponents'
    private static string GetOpponent( Match match )
    {
        string opponentStr = (match == null) ? DXString.Get( "analyze.opps" ) : match.Team2Name;

        return $"{DXString.Get( "match.opp.vs" )} {opponentStr}";
    }

    // 'Junior Nationals'
    private static string GetTournament( Tournament tournament )
    {
        return tournament?.Name;
    }

    // 'Fall 2020'
    private static string GetSeason( Season season )
    {
        return season.Name;
    }

    // 'Career'
    private static string GetCareer()
    {
        return DXString.Get( "analyze.career" );
    }

    // 'September 10, 2020'
    private static string GetDate( DateTimeOffset date )
    {
        return DXUtils.MonthFromDate( date );
    }

    // 'Set 1'
    private static string GetSet( Set set )
    {
        string setStr = DXString.Get( "set.singular" );

        return $"{setStr} {set.Number}";
    }

    // 'Won (3-1)' or 'Record (25-2)'
    private static string GetRecord( int won, int lost, int tied, bool cumulative )
    {
        string resource = cumulative ? "export.record" : ((won == lost) ? "match.tied" : ((won > lost) ? "match.won" : "match.lost"));
        string tiedStr = (tied > 0) ? $"-{tied}" : string.Empty;

        return $"{DXString.Get( resource )} ({won}-{lost}{tiedStr})";
    }
}

//
