using System;
using System.Data.SqlClient;
using System.Text.Json.Nodes;

namespace HorseRacingPredictor.Football.Database
{
    internal class Odds : HorseRacingPredictor.Football.Manager.Database
    {
        public void Upsert(SqlConnection connection, JsonNode bookmakers, int fixtureId)
        {
            try
            {
                // Aggiungiamo log per tracciare la struttura dei dati
                LogError($"Inizio elaborazione quote per fixture {fixtureId} con {bookmakers?.AsArray().Count ?? 0} bookmakers", null);

                // Per ogni bookmaker
                foreach (var bookmaker in bookmakers.AsArray())
                {
                    int bookmakerId = bookmaker["id"].GetValue<int>();
                    var bets = bookmaker["bets"];

                    // Cerchiamo le quote di tipo Match Winner (1X2)
                    foreach (var bet in bets.AsArray())
                    {
                        // Gestiamo in modo pił sicuro il recupero di valori dal JSON
                        string betName = GetStringValueSafe(bet, "name");

                        // Log per debug
                        LogError($"Elaborazione bet: '{betName}' per bookmaker {bookmakerId}", null);

                        // Determina il tipo di scommessa (assumiamo che esista una tabella BetType)
                        int betTypeId = GetBetTypeId(connection, betName);

                        // Se non riusciamo a determinare il tipo di scommessa, continuiamo con la prossima
                        if (betTypeId == 0) continue;

                        // Estrai e salva le quote
                        foreach (var value in bet["values"].AsArray())
                        {
                            // Gestiamo in modo pił sicuro il recupero di valori dal JSON
                            string valueType = GetStringValueSafe(value, "value");
                            decimal oddValue = GetDecimalValueSafe(value, "odd");

                            // Log per debug
                            LogError($"Elaborazione quota: tipo={valueType}, valore={oddValue}", null);

                            if (oddValue > 0) // Verifichiamo che il valore sia valido
                            {
                                var query = @"
                                            IF EXISTS (SELECT 1 FROM Odd WHERE fixture_id = @fixture_id AND bookmaker_id = @bookmaker_id 
                                                      AND bet_type_id = @bet_type_id AND value = @value)
                                            BEGIN
                                                UPDATE Odd 
                                                SET odd = @odd, update_time = @update_time
                                                WHERE fixture_id = @fixture_id AND bookmaker_id = @bookmaker_id 
                                                  AND bet_type_id = @bet_type_id AND value = @value
                                            END
                                            ELSE
                                            BEGIN
                                                INSERT INTO Odd (fixture_id, bookmaker_id, bet_type_id, value, odd, update_time)
                                                VALUES (@fixture_id, @bookmaker_id, @bet_type_id, @value, @odd, @update_time)
                                            END";

                                using (var command = new SqlCommand(query, connection))
                                {
                                    command.Parameters.AddWithValue("@fixture_id", fixtureId);
                                    command.Parameters.AddWithValue("@bookmaker_id", bookmakerId);
                                    command.Parameters.AddWithValue("@bet_type_id", betTypeId);
                                    command.Parameters.AddWithValue("@value", valueType);
                                    command.Parameters.AddWithValue("@odd", oddValue);
                                    command.Parameters.AddWithValue("@update_time", DateTime.Now);
                                    command.ExecuteNonQuery();
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogError("l'upsert delle quote", ex);
            }
        }

        /// <summary>
        /// Ottiene l'ID del tipo di scommessa in base al nome
        /// </summary>
        private int GetBetTypeId(SqlConnection connection, string betTypeName)
        {
            try
            {
                // Prima verifica se il tipo di scommessa esiste
                var queryCheck = "SELECT bet_type_id FROM BetType WHERE name = @name";
                using (var command = new SqlCommand(queryCheck, connection))
                {
                    command.Parameters.AddWithValue("@name", betTypeName);
                    var result = command.ExecuteScalar();

                    if (result != null && result != DBNull.Value)
                    {
                        return Convert.ToInt32(result);
                    }
                    else
                    {
                        // Se non esiste, inseriscilo (con un ID progressivo)
                        var queryInsert = @"
                                    DECLARE @next_id INT;
                                    SELECT @next_id = ISNULL(MAX(bet_type_id), 0) + 1 FROM BetType;
                                    
                                    INSERT INTO BetType (bet_type_id, name)
                                    VALUES (@next_id, @name);
                                    
                                    SELECT @next_id;";

                        using (var insertCommand = new SqlCommand(queryInsert, connection))
                        {
                            insertCommand.Parameters.AddWithValue("@name", betTypeName);
                            return Convert.ToInt32(insertCommand.ExecuteScalar());
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogError($"determinazione bet_type_id per '{betTypeName}'", ex);
                return 0;
            }
        }

        /// <summary>
        /// Ottiene un valore stringa da un JsonNode in modo sicuro
        /// </summary>
        private string GetStringValueSafe(JsonNode node, string propertyName)
        {
            try
            {
                if (node == null || node[propertyName] == null)
                    return string.Empty;

                var value = node[propertyName];

                // Gestiamo diversi tipi di nodi
                if (value.GetValueKind() == System.Text.Json.JsonValueKind.String)
                    return value.GetValue<string>();
                else if (value.GetValueKind() == System.Text.Json.JsonValueKind.Number)
                    return value.GetValue<decimal>().ToString();
                else
                    return value.ToString();
            }
            catch (Exception ex)
            {
                LogError($"estrazione valore stringa per proprietą '{propertyName}'", ex);
                return string.Empty;
            }
        }

        /// <summary>
        /// Ottiene un valore decimale da un JsonNode in modo sicuro
        /// </summary>
        private decimal GetDecimalValueSafe(JsonNode node, string propertyName)
        {
            try
            {
                if (node == null || node[propertyName] == null)
                    return 0;

                var value = node[propertyName];

                // Gestiamo diversi tipi di nodi
                if (value.GetValueKind() == System.Text.Json.JsonValueKind.Number)
                {
                    // Assicuriamoci che il valore sia esattamente quello originale
                    return value.GetValue<decimal>();
                }
                else if (value.GetValueKind() == System.Text.Json.JsonValueKind.String)
                {
                    // Utilizziamo InvariantCulture per garantire una corretta interpretazione dei decimali
                    if (decimal.TryParse(value.GetValue<string>(),
                        System.Globalization.NumberStyles.Any,
                        System.Globalization.CultureInfo.InvariantCulture,
                        out decimal result))
                    {
                        return result;
                    }
                }

                // Aggiungiamo un log pił dettagliato per aiutare il debug
                LogError($"Impossibile convertire '{value}' (tipo: {value.GetValueKind()}) in decimal per proprietą '{propertyName}'", null);
                return 0;
            }
            catch (Exception ex)
            {
                LogError($"estrazione valore decimal per proprietą '{propertyName}'", ex);
                return 0;
            }
        }
    }
}
