using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Text.Json.Nodes;
using System.Threading.Tasks;

namespace HorseRacingPredictor.Football.Database
{
    internal class FixtureLeague : HorseRacingPredictor.Football.Manager.Database
    {
        public void Upsert(SqlConnection connection, SqlTransaction transaction, int fixtureId, int leagueId, JsonNode leagueData)
        {
            try
            {
                // Estrai i valori prima della query per utilizzarli nel log
                string round = leagueData["round"]?.GetValue<string>() ?? "";
                bool? standings = leagueData["standings"]?.GetValue<bool?>();
                string standingsValue = standings.HasValue ? standings.Value.ToString() : "NULL";

                // Log dell'operazione prima di tentare l'upsert
                LogDebugInfo($"Tentativo di upsert FixtureLeague: fixture_id={fixtureId}, league_id={leagueId}, round='{round}', standings={standingsValue}");

                var query = @"
                                IF EXISTS (SELECT 1 FROM FixtureLeague WHERE fixture_id = @fixture_id AND league_id = @league_id)
                                BEGIN
                                    UPDATE FixtureLeague 
                                    SET round = @round, standings = @standings 
                                    WHERE fixture_id = @fixture_id AND league_id = @league_id
                                END
                                ELSE
                                BEGIN
                                    INSERT INTO FixtureLeague (fixture_id, league_id, round, standings)
                                    VALUES (@fixture_id, @league_id, @round, @standings)
                                END";

                using (var command = new SqlCommand(query, connection, transaction))
                {
                    command.Parameters.AddWithValue("@fixture_id", fixtureId);
                    command.Parameters.AddWithValue("@league_id", leagueId);
                    command.Parameters.AddWithValue("@round", round);
                    command.Parameters.AddWithValue("@standings", standings.HasValue ? (object)standings.Value : DBNull.Value);

                    command.ExecuteNonQuery();
                }

                // Log di successo dopo l'operazione
                LogDebugInfo($"Upsert FixtureLeague completato con successo: fixture_id={fixtureId}, league_id={leagueId}");
            }
            catch (Exception ex)
            {
                // Log dettagliato dell'errore
                StringBuilder detailedError = new StringBuilder();
                detailedError.AppendLine($"Errore durante l'upsert della relazione fixture-league:");
                detailedError.AppendLine($"- fixture_id: {fixtureId}");
                detailedError.AppendLine($"- league_id: {leagueId}");
                detailedError.AppendLine($"- round: '{leagueData["round"]?.ToString() ?? "NULL"}'");
                detailedError.AppendLine($"- standings: {leagueData["standings"]?.ToString() ?? "NULL"}");
                detailedError.AppendLine($"- leagueData: {leagueData?.ToString() ?? "NULL"}");
                detailedError.AppendLine($"- Messaggio errore: {ex.Message}");

                if (ex.InnerException != null)
                {
                    detailedError.AppendLine($"- Inner exception: {ex.InnerException.Message}");
                }

                // Controlla se la fixture esiste
                CheckIfFixtureExists(connection, transaction, fixtureId, detailedError);

                // Controlla se la league esiste
                CheckIfLeagueExists(connection, transaction, leagueId, detailedError);

                LogError("l'upsert della relazione fixture-league", new Exception(detailedError.ToString(), ex));
                throw; // Rilancia l'eccezione per il rollback della transazione
            }
        }

        /// <summary>
        /// Verifica se una fixture esiste nel database e aggiunge l'informazione al log
        /// </summary>
        private void CheckIfFixtureExists(SqlConnection connection, SqlTransaction transaction, int fixtureId, StringBuilder logBuilder)
        {
            try
            {
                using (var cmd = new SqlCommand("SELECT COUNT(1) FROM Fixture WHERE fixture_id = @id", connection, transaction))
                {
                    cmd.Parameters.AddWithValue("@id", fixtureId);
                    int count = Convert.ToInt32(cmd.ExecuteScalar());
                    logBuilder.AppendLine($"- Fixture con ID {fixtureId} {(count > 0 ? "esiste" : "NON esiste")} nel database");
                }
            }
            catch (Exception ex)
            {
                logBuilder.AppendLine($"- Errore durante la verifica dell'esistenza della fixture: {ex.Message}");
            }
        }

        /// <summary>
        /// Verifica se una league esiste nel database e aggiunge l'informazione al log
        /// </summary>
        private void CheckIfLeagueExists(SqlConnection connection, SqlTransaction transaction, int leagueId, StringBuilder logBuilder)
        {
            try
            {
                using (var cmd = new SqlCommand("SELECT COUNT(1) FROM League WHERE league_id = @id", connection, transaction))
                {
                    cmd.Parameters.AddWithValue("@id", leagueId);
                    int count = Convert.ToInt32(cmd.ExecuteScalar());
                    logBuilder.AppendLine($"- League con ID {leagueId} {(count > 0 ? "esiste" : "NON esiste")} nel database");
                }
            }
            catch (Exception ex)
            {
                logBuilder.AppendLine($"- Errore durante la verifica dell'esistenza della league: {ex.Message}");
            }
        }

        /// <summary>
        /// Logga informazioni di debug (utile per tracciare il flusso di esecuzione)
        /// </summary>
        private void LogDebugInfo(string message)
        {
            try
            {
                // Utilizziamo LogError con exception null come metodo per loggare informazioni di debug
                LogError("DEBUG INFO", new Exception(message));
            }
            catch
            {
                // Ignoriamo eventuali errori nel logging di debug
            }
        }
    }
}
