using CsvHelper;
using CsvHelper.Configuration;
using DvApi32;
using Serilog.Core;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WK5.Core;
using WK5.Core.Models;
using WK5.Core.Services;

namespace KarleyUpdate
{
    internal class MietenImport
    {
        private List<MietenZuordnung> _artikelZuordnungen = new();
        public MietenImport()
        {
            using (TextReader reader = new StreamReader(@"\\srv01\daten\w4\tmp\MietenZuordnung.csv", Encoding.GetEncoding("ISO-8859-1")))
            {
                CsvConfiguration configuration = new CsvConfiguration(CultureInfo.GetCultureInfo("de-DE"));
                configuration.BadDataFound = null;
                configuration.Encoding = Encoding.GetEncoding("ISO-8859-1");
                using (var csv = new CsvReader(reader, configuration))
                {
                    _artikelZuordnungen = csv.GetRecords<MietenZuordnung>().ToList();
                }
            }
        }
        public async Task RunAsync(Logger logger)
        {
            using MySqlController2 mySqlController = new MySqlController2();
            using FbController2 fbController = new FbController2();
            
            

            DataTable data = await fbController.SelectDataAsync("SELECT * FROM ARTIKEL WHERE ARTI_L_MIETE = 'Y' AND ARTI_L_INAKTIV = 'N'");
            List<int> bereitsGelöscht = new();

            foreach (DataRow row in data.Rows)
            {
                string artikelnummer = row.Field<string>("ARTI_A_NR") ?? throw new NullReferenceException(nameof(artikelnummer));

                var zuordnung = _artikelZuordnungen.FirstOrDefault(x => x.ArtikelnummerOriginal.Equals(artikelnummer, StringComparison.OrdinalIgnoreCase));

                int product_id = await GetProductIdAsync(zuordnung is null ? artikelnummer : zuordnung.ArtikelnummerZugeordnet, mySqlController);

                if (product_id is > 0)
                {
                    if (!bereitsGelöscht.Contains(product_id))
                    {
                        logger.Information("Lösche Termine von Online ProductId: {product_id}", product_id);
                        mySqlController.AddParameter("@PRODUCT_ID", product_id);
                        await mySqlController.QueryAsync("DELETE FROM karley_mieten WHERE product_id = @PRODUCT_ID");
                        bereitsGelöscht.Add(product_id);
                    }

                    await foreach (var termin in GetBlockierteTermineAsync(fbController, artikelnummer))
                    {
                        logger.Information("Termin hinzufügen ProductId: {product_id}; Termin: {Termin}", product_id, termin.ToShortDateString());
                        // Termine können sich aufgrund des Puffers überschneiden. Daher ein INSERT IGNORE
                        mySqlController.AddParameter("@PRODUCT_ID", product_id);
                        mySqlController.AddParameter("@TERMIN", termin);
                        await mySqlController.QueryAsync("INSERT IGNORE INTO `karley_mieten` (`product_id`, `termin`) VALUES (@PRODUCT_ID, @TERMIN)");

                    }
                }
            }
        }

        private async Task<int> GetProductIdAsync(string artikelnummer, MySqlController2 mySqlController)
        {
            mySqlController.AddParameter("@ARTIKELNUMMER", artikelnummer.ToUpper());
            int product_id = Convert.ToInt32(await mySqlController.FetchObjectAsync("SELECT product_id from `product` where upper(`model`) = @ARTIKELNUMMER"));

            return product_id;
        }

        private async IAsyncEnumerable<DateTime> GetBlockierteTermineAsync(FbController2 fbController, string artikelnummer)
        {
            ArtikelService artikelService = new ArtikelService();


            var termine = await artikelService.GetTermineAsync(artikelnummer, true, fbController);

            foreach (var termin in termine)
            {
                // Angebotene sind immer noch verfügbar
                if (termin.IsAngeboten)
                {
                    continue;
                }

                DateTime start = termin.Start;
                DateTime ende = termin.Ende.AddDays(3);

                if (ende.DayOfWeek is DayOfWeek.Sunday or DayOfWeek.Saturday)
                {
                    ende = ende.AddDays(2);
                }

                do
                {
                    yield return start;
                    start = start.AddDays(1);
                }
                while (start < ende);
            }
        }

        private class MietenZuordnung
        {
            public string ArtikelnummerOriginal { get; set; } = string.Empty;
            public string ArtikelnummerZugeordnet { get; set; } = string.Empty;
        }
    }
}
