using ExcelDataReader;
using Microsoft.AspNetCore.Components.Forms;
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.Models;

namespace WK5.Core.Services
{
    public class PreislistenImportService
    {
        

        public List<ColumnZuordnung> ZuordnungColumns { get; set; } = new List<ColumnZuordnung>();
        public DataTable? Data { get; private set; }
        public Lieferant? SelectedLieferant { get; set; }
        public bool UpdateEinkaufspreise { get; set; }
        public int MaxIndex
        {
            get
            {
                if (Data is null)
                {
                    return -1;
                }

                if (Data.Columns.Count > 20)
                {
                    return 20;
                }

                return Data.Columns.Count;
            }
        }

        
        public async Task ReadFileAsync(IBrowserFile file)
        {
            
            ZuordnungColumns.Clear();

            if (Path.GetExtension(file.Name).Equals(".xlsx", StringComparison.OrdinalIgnoreCase))
            {
                Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
                byte[] buffer = new byte[file.Size];

                await using MemoryStream stream = new MemoryStream(buffer);
                await file.OpenReadStream(file.Size).CopyToAsync(stream);
                IExcelDataReader excelDataReader = ExcelReaderFactory.CreateOpenXmlReader(stream);

                var _dataSet = excelDataReader.AsDataSet();
                if (_dataSet.Tables.Count > 0)
                {
                    Data = ClearEmptyRows(_dataSet.Tables[0]);
                    
                    for (int i = 0; i < MaxIndex; i++)
                    {
                        ZuordnungColumns.Add(new ColumnZuordnung(Data.Columns[i], i));
                    }
                }

            }
            else if(Path.GetExtension(file.Name).Equals(".csv", StringComparison.OrdinalIgnoreCase))
            {
                Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
                byte[] buffer = new byte[file.Size];
                

                await using MemoryStream stream = new MemoryStream(buffer);
                await file.OpenReadStream(file.Size).CopyToAsync(stream);
                IExcelDataReader csvDataReader = ExcelReaderFactory.CreateCsvReader(stream);

                var _dataSet = csvDataReader.AsDataSet();
                if (_dataSet.Tables.Count > 0)
                {
                    Data = ClearEmptyRows(_dataSet.Tables[0]);

                    for (int i = 0; i < MaxIndex; i++)
                    {
                        ZuordnungColumns.Add(new ColumnZuordnung(Data.Columns[i], i));
                    }
                }
            }
        }

        public IEnumerable<DataRow> GetDataRows()
        {
            foreach (DataRow row in Data.Rows)
            {
                yield return row;
            }
        }

        public void ClearWrongFormattedRows()
        {
            int artikelnummerIndex = ZuordnungColumns.First(x => x.IsArtikelnummerColumn).Index;
            int preisIndex = ZuordnungColumns.First(x => x.IsPreisColumn).Index;
            int händlerPreisIndex = ZuordnungColumns.First(x => x.IsHändlerPreisColumn).Index;
            if (Data is not null)
            {
                List<int> indexesToRemove = new List<int>();

                foreach (DataRow row in Data.Rows)
                {
                    string? artikelnummer = row[artikelnummerIndex].ToString();
                    string preisString = (row[preisIndex].ToString() ?? string.Empty).Replace(",",".");
                    string händlerPreisString  = (row[händlerPreisIndex].ToString() ?? string.Empty).Replace(",", ".");

                    if (!decimal.TryParse(preisString, out decimal preis) || string.IsNullOrEmpty(artikelnummer) || !decimal.TryParse(händlerPreisString, out decimal händlerPreis))
                    {
                        indexesToRemove.Add(Data.Rows.IndexOf(row));
                    }
                }

                foreach (var index in indexesToRemove.OrderByDescending(x => x))
                {
                    Data.Rows.RemoveAt(index);
                }
            }
        }

        private DataTable ClearEmptyRows(DataTable table)
        {
            int maxIndex = table.Columns.Count > 20 ? 20 : table.Columns.Count;
            DataTable data = table.Copy();
            List<int> indexesToRemove = new List<int>();
            foreach (DataRow row in table.Rows)
            {
                bool hasData = false;
                for (int i = 0; i < maxIndex; i++)
                {
                    if (!string.IsNullOrWhiteSpace(row[i].ToString()))
                    {
                        hasData = true;
                        break;
                    }
                }

                if (!hasData)
                {
                    indexesToRemove.Add(table.Rows.IndexOf(row));
                }
            }

            foreach (var index in indexesToRemove.OrderByDescending(x => x))
            {
                data.Rows.RemoveAt(index);
            }

            return data;
        }


        public IEnumerable<PreislistenImportArtikel> GetImportArtikel()
        {
            int artikelnummerIndex = ZuordnungColumns.First(x => x.IsArtikelnummerColumn).Index;
            int preisIndex = ZuordnungColumns.First(x => x.IsPreisColumn).Index;
            int händlerPreisIndex = ZuordnungColumns.First(x => x.IsHändlerPreisColumn).Index;
            if (Data is not null)
            {
                foreach (DataRow row in Data.Rows)
                {
                    string? artikelnummer = row[artikelnummerIndex].ToString();
                    string preisString = (row[preisIndex].ToString() ?? string.Empty).Replace(",", ".");
                    string händlerPreisString = (row[händlerPreisIndex].ToString() ?? string.Empty).Replace(",", ".");

                    if (decimal.TryParse(preisString, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out decimal preis) && decimal.TryParse(händlerPreisString, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out decimal händlerPreis) && !string.IsNullOrEmpty(artikelnummer))
                    {
                        yield return new PreislistenImportArtikel(artikelnummer, preis, händlerPreis);
                    }
                }
            }
        }

        public async Task<bool> ImportiereAsync(PreislistenImportArtikel artikel, FbController2 fbController)
        {

            if(UpdateEinkaufspreise)
            {
                if (SelectedLieferant is not null)
                {
                    bool artikelnummerExists = await fbController.SelectRowAsync<string?>(@"SELECT 
ARLI_A_ARTIKELNR 
FROM LIEFERANTENARTIKEL 
WHERE UPPER(ARLI_A_ARTIKELNR) = @ARLI_A_ARTIKELNR AND ARLI_N_LIEFNR = @ARLI_N_LIEFNR", new { ARLI_A_ARTIKELNR  = artikel.Artikelnummer.ToUpper(), ARLI_N_LIEFNR = SelectedLieferant.LIEF_N_NR }) != null;

                    if (artikelnummerExists)
                    {
                        fbController.AddParameter("@ARLI_N_PREIS", artikel.Preis);                        
                        fbController.AddParameter("@ARLI_A_ARTIKELNR", artikel.Artikelnummer.ToUpper());
                        fbController.AddParameter("@ARLI_N_LIEFNR", SelectedLieferant.LIEF_N_NR);
                        await fbController.QueryAsync(@"UPDATE LIEFERANTENARTIKEL SET 
ARLI_N_PREIS = @ARLI_N_PREIS,
ARLI_N_WAEHRUNGSPREIS = @ARLI_N_PREIS,
ARLI_D_LETZAEND = CURRENT_TIMESTAMP,
ARLI_TIMESTAMP = CURRENT_TIMESTAMP
WHERE UPPER(ARLI_A_ARTIKELNR) = @ARLI_A_ARTIKELNR AND ARLI_N_LIEFNR = @ARLI_N_LIEFNR");

                        return true;
                    }
                }
            }
            else
            {

                bool artikelnummerExists = await fbController.SelectRowAsync<string?>(@"SELECT 
ARTI_A_NR 
FROM ARTIKEL 
WHERE UPPER(ARTI_A_NR) = @ARTI_A_NR", new { ARTI_A_NR = artikel.Artikelnummer.ToUpper() }) != null;

                if (artikelnummerExists)
                {
                    fbController.AddParameter("@FIRMENPREISLISTE", artikel.Preis);
                    // Preis ist gleich aktueller Preis - alter prozentsatz
                    fbController.AddParameter("@HAENDLERPREISLISTE", artikel.Händlerpreis);
                    fbController.AddParameter("@LISTENPREIS", artikel.Preis);
                    fbController.AddParameter("@DIRECTSHOP_PREIS", artikel.Preis);
                    fbController.AddParameter("@ARTIKELNUMMER", artikel.Artikelnummer.ToUpper());
                    await fbController.QueryAsync(@"UPDATE ARTIKEL SET 
ARTI_N_VK1 = @FIRMENPREISLISTE, 
ARTI_N_VK2 = @HAENDLERPREISLISTE, 
ARTI_N_VK4  = @LISTENPREIS, 
ARTI_N_VK5 = @DIRECTSHOP_PREIS 
WHERE ARTI_A_NR = @ARTIKELNUMMER AND ARTI_L_FIXPREIS = 'Y'");
                    return true;
                }
            }

            return false;
        }
        
    }

    public class PreislistenImportArtikel
    {
        public string Artikelnummer { get; }
        public decimal Preis { get; }
        public decimal Händlerpreis { get; set; }
        public PreislistenImportArtikel(string artikelnummer, decimal preis, decimal händlerPreis)
        {
            Artikelnummer = artikelnummer.Trim();
            Preis = preis;
            Händlerpreis = händlerPreis;
        }
    }
    public class ColumnZuordnung
    {
        public DataColumn Column { get; }
        public int Index { get; }
        public bool IsArtikelnummerColumn => ZuordnungsIndex is 0;
        public bool IsPreisColumn => ZuordnungsIndex is 1;
        public bool IsHändlerPreisColumn => ZuordnungsIndex is 2;

        public int ZuordnungsIndex { get; set; } = -1;

        public ColumnZuordnung(DataColumn column, int index)
        {
            Column = column;
            Index = index;
        }
    }
}
