using System;
using System.Data;
using System.Text.Json;
using HorseRacingPredictor.HorseRacing.API;

namespace HorseRacingPredictor.HorseRacing
{
    /// <summary>
    /// Gestore centralizzato per la sezione Corse dei Cavalli.
    /// Scarica i dati da The Racing API e li converte in DataTable.
    /// </summary>
    public class Main
    {
        private RacingApiClient _client;

        public Main(string username, string password)
        {
            _client = new RacingApiClient(username, password);
        }

        /// <summary>
        /// Aggiorna le credenziali API
        /// </summary>
        public void UpdateCredentials(string username, string password)
        {
            _client = new RacingApiClient(username, password);
        }

        /// <summary>
        /// Scarica le racecard (programma corse) per oggi o domani e le restituisce come DataTable
        /// </summary>
        public DataTable GetRacecards(string day, IProgress<int> progress = null, IProgress<string> status = null)
        {
            try
            {
                status?.Report("Connessione a The Racing API...");
                progress?.Report(10);

                var response = _client.GetRacecardsFree(day);
                progress?.Report(60);

                status?.Report("Elaborazione racecard...");
                var table = ParseRacecardsResponse(response.Content);
                progress?.Report(100);

                status?.Report($"Trovate {table.Rows.Count} corse");
                return table;
            }
            catch (Exception ex)
            {
                status?.Report($"Errore: {ex.Message}");
                return CreateEmptyRacecardsTable();
            }
        }

        /// <summary>
        /// Scarica i risultati per un intervallo di date
        /// </summary>
        public DataTable GetResults(DateTime startDate, DateTime endDate,
            IProgress<int> progress = null, IProgress<string> status = null)
        {
            try
            {
                status?.Report("Scaricamento risultati...");
                progress?.Report(10);

                var response = _client.GetResults(startDate, endDate);
                progress?.Report(60);

                status?.Report("Elaborazione risultati...");
                var table = ParseResultsResponse(response.Content);
                progress?.Report(100);

                status?.Report($"Trovati {table.Rows.Count} risultati");
                return table;
            }
            catch (Exception ex)
            {
                status?.Report($"Errore: {ex.Message}");
                return CreateEmptyResultsTable();
            }
        }

        #region DataTable creation

        private DataTable CreateEmptyRacecardsTable()
        {
            var dt = new DataTable();
            dt.Columns.Add("Ora", typeof(string));
            dt.Columns.Add("Ippodromo", typeof(string));
            dt.Columns.Add("Regione", typeof(string));
            dt.Columns.Add("Corsa", typeof(string));
            dt.Columns.Add("Distanza", typeof(string));
            dt.Columns.Add("Tipo", typeof(string));
            dt.Columns.Add("Classe", typeof(string));
            dt.Columns.Add("Terreno", typeof(string));
            dt.Columns.Add("N. Corridori", typeof(int));
            dt.Columns.Add("Età", typeof(string));
            dt.Columns.Add("Premio", typeof(string));
            return dt;
        }

        private DataTable CreateEmptyResultsTable()
        {
            var dt = new DataTable();
            dt.Columns.Add("Data", typeof(string));
            dt.Columns.Add("Ippodromo", typeof(string));
            dt.Columns.Add("Corsa", typeof(string));
            dt.Columns.Add("Distanza", typeof(string));
            dt.Columns.Add("Terreno", typeof(string));
            dt.Columns.Add("1° Classificato", typeof(string));
            dt.Columns.Add("2° Classificato", typeof(string));
            dt.Columns.Add("3° Classificato", typeof(string));
            dt.Columns.Add("Fantino 1°", typeof(string));
            dt.Columns.Add("SP 1°", typeof(string));
            return dt;
        }

        #endregion

        #region JSON Parsing

        private DataTable ParseRacecardsResponse(string json)
        {
            var dt = CreateEmptyRacecardsTable();
            if (string.IsNullOrEmpty(json)) return dt;

            try
            {
                using (var doc = JsonDocument.Parse(json))
                {
                    var root = doc.RootElement;

                    if (!root.TryGetProperty("racecards", out var racecardsEl))
                        return dt;

                    foreach (var rc in racecardsEl.EnumerateArray())
                    {
                        try
                        {
                            var row = dt.NewRow();

                            row["Ora"] = GetString(rc, "off_time", "");
                            row["Ippodromo"] = GetString(rc, "course", "");
                            row["Regione"] = GetString(rc, "region", "");
                            row["Corsa"] = GetString(rc, "race_name", "");
                            row["Distanza"] = GetString(rc, "distance", "");
                            row["Tipo"] = GetString(rc, "type", "");
                            row["Classe"] = GetString(rc, "race_class", "");
                            row["Terreno"] = GetString(rc, "going", "");
                            row["Età"] = GetString(rc, "age_band", "");
                            row["Premio"] = GetString(rc, "prize", "");

                            if (rc.TryGetProperty("runners", out var runnersEl) &&
                                runnersEl.ValueKind == JsonValueKind.Array)
                            {
                                row["N. Corridori"] = runnersEl.GetArrayLength();
                            }
                            else if (rc.TryGetProperty("field_size", out var fsEl) &&
                                     fsEl.ValueKind == JsonValueKind.Number)
                            {
                                row["N. Corridori"] = fsEl.GetInt32();
                            }
                            else
                            {
                                row["N. Corridori"] = 0;
                            }

                            dt.Rows.Add(row);
                        }
                        catch
                        {
                            // Salta righe problematiche
                        }
                    }
                }
            }
            catch
            {
                // Restituisci tabella vuota in caso di errore di parsing
            }

            return dt;
        }

        private DataTable ParseResultsResponse(string json)
        {
            var dt = CreateEmptyResultsTable();
            if (string.IsNullOrEmpty(json)) return dt;

            try
            {
                using (var doc = JsonDocument.Parse(json))
                {
                    var root = doc.RootElement;

                    if (!root.TryGetProperty("results", out var resultsEl))
                        return dt;

                    foreach (var res in resultsEl.EnumerateArray())
                    {
                        try
                        {
                            var row = dt.NewRow();

                            row["Data"] = GetString(res, "date", "");
                            row["Ippodromo"] = GetString(res, "course", "");
                            row["Corsa"] = GetString(res, "race_name", "");
                            row["Distanza"] = GetString(res, "distance", "");
                            row["Terreno"] = GetString(res, "going", "");

                            if (res.TryGetProperty("runners", out var runnersEl) &&
                                runnersEl.ValueKind == JsonValueKind.Array)
                            {
                                int idx = 0;
                                foreach (var runner in runnersEl.EnumerateArray())
                                {
                                    var pos = GetString(runner, "position", "");
                                    if (pos == "1" || idx == 0)
                                    {
                                        row["1° Classificato"] = GetString(runner, "horse", "");
                                        row["Fantino 1°"] = GetString(runner, "jockey", "");
                                        row["SP 1°"] = GetString(runner, "sp", "");
                                    }
                                    else if (pos == "2" || idx == 1)
                                    {
                                        row["2° Classificato"] = GetString(runner, "horse", "");
                                    }
                                    else if (pos == "3" || idx == 2)
                                    {
                                        row["3° Classificato"] = GetString(runner, "horse", "");
                                    }
                                    idx++;
                                    if (idx >= 3) break;
                                }
                            }

                            dt.Rows.Add(row);
                        }
                        catch
                        {
                            // Salta righe problematiche
                        }
                    }
                }
            }
            catch
            {
                // Restituisci tabella vuota in caso di errore di parsing
            }

            return dt;
        }

        private static string GetString(JsonElement el, string property, string defaultValue)
        {
            if (el.TryGetProperty(property, out var prop) && prop.ValueKind == JsonValueKind.String)
                return prop.GetString() ?? defaultValue;
            if (el.TryGetProperty(property, out prop) && prop.ValueKind == JsonValueKind.Number)
                return prop.ToString();
            return defaultValue;
        }

        #endregion
    }
}
