using Microsoft.EntityFrameworkCore;
using System.Collections.Immutable;
using WerksverkaufScanner.Data;
using static System.Net.Mime.MediaTypeNames;

public class StammdatenCache
{
    private readonly IDbContextFactory<ScannerDb> _dbFactory;
    private readonly SemaphoreSlim _lock = new(1, 1);

    // Hauptspeicher: Artikel nach ID
   private ImmutableDictionary<int, Artikel> _byId = ImmutableDictionary<int, Artikel>.Empty;

    private List<Artikel> _allArtikel = new();


    // Nachschlage-Indizes: Code -> ArtikelId
    private Dictionary<string, int> _indexBarcode = new(StringComparer.OrdinalIgnoreCase);
    private Dictionary<string, int> _indexArtikelnummer = new(StringComparer.OrdinalIgnoreCase);

    public StammdatenCache(IDbContextFactory<ScannerDb> dbFactory) => _dbFactory = dbFactory;

    //public async Task RefreshAsync()
    //{
    //    await _lock.WaitAsync();
    //    try
    //    {
    //        await using var db = await _dbFactory.CreateDbContextAsync();

    //        // nur die benötigten Spalten laden (performant)
    //        var list = await db.Artikel
    //            .AsNoTracking()
    //            .OrderBy(a => a.ArtikelNummer)
    //            .ThenBy(a => a.ArtikelId)
    //            .ThenBy(a => a.Variante)
    //            .Select(a => new Artikel
    //            {
    //                ArtikelId = a.ArtikelId,
    //                ArtikelVariantenId = a.ArtikelVariantenId,
    //                Variante = a.Variante,
    //                ArtikelNummer = a.ArtikelNummer ?? "",
    //                Barcode = a.Barcode ?? "",
    //                Bezeichnung = a.Bezeichnung ?? "",
    //                Bontext = a.Bontext ?? "",
    //                NettoGewicht = a.NettoGewicht,
    //                Mengeneinheit = a.Mengeneinheit ?? "",
    //                BasisMenge = a.BasisMenge,
    //                AS400ArtikelNummer = a.AS400ArtikelNummer ?? "",
    //                Farbe = a.Farbe ?? "",
    //                Text = a.Text ?? ""
    //            })
    //            .ToListAsync();


    //        // 1) byId aufbauen (ID ist eindeutig)
    //        _byId = list.ToImmutableDictionary(a => a.ArtikelVariantenId, a => a);

    //        // 2) Indizes aufbauen – Kollisionen tolerant behandeln
    //        _indexBarcode = new(StringComparer.OrdinalIgnoreCase);
    //        _indexArtikelnummer = new(StringComparer.OrdinalIgnoreCase);

    //        foreach (var a in list)
    //        {
    //            if (!string.IsNullOrWhiteSpace(a.Barcode))
    //            {
    //                var key = Normalize(a.Barcode!);
    //                // first-wins (kein Fehler bei Duplikat)
    //                if (!_indexBarcode.ContainsKey(key))
    //                    _indexBarcode[key] = a.ArtikelId;
    //            }

    //            if (!string.IsNullOrWhiteSpace(a.ArtikelNummer))
    //            {
    //                var key = Normalize(a.ArtikelNummer!);
    //                if (!_indexArtikelnummer.ContainsKey(key))
    //                    _indexArtikelnummer[key] = a.ArtikelId;
    //            }
    //        }
    //    }
    //    finally
    //    {
    //        _lock.Release();
    //    }
    //}

    //public IReadOnlyCollection<Artikel> GetArtikel() => _byId.Values.ToList();

    public async Task RefreshAsync()
    {
        await _lock.WaitAsync();
        try
        {
            await using var db = await _dbFactory.CreateDbContextAsync();

            var list = await db.Artikel
                .AsNoTracking()
                .OrderBy(a => a.ArtikelNummer)
                .ThenBy(a => a.ArtikelId)
                .ThenBy(a => a.Variante)
                .Select(a => new Artikel
                {
                    ArtikelId = a.ArtikelId,
                    ArtikelVariantenId = a.ArtikelVariantenId,
                    Variante = a.Variante,
                    ArtikelNummer = a.ArtikelNummer ?? "",
                    Barcode = a.Barcode ?? "",
                    Bezeichnung = a.Bezeichnung ?? "",
                    Bontext = a.Bontext ?? "",
                    NettoGewicht = a.NettoGewicht,
                    Mengeneinheit = a.Mengeneinheit ?? "",
                    BasisMenge = a.BasisMenge,
                    AS400ArtikelNummer = a.AS400ArtikelNummer ?? "",
                    Farbe = a.Farbe ?? "",
                    Text = a.Text ?? ""
                })
                .ToListAsync();

            _allArtikel = list;

            _byId = list.ToImmutableDictionary(a => a.ArtikelVariantenId, a => a);
            // ... Indizes aufbauen ...
        }
        finally
        {
            _lock.Release();
        }
    }

    public IReadOnlyList<Artikel> GetArtikel() => _allArtikel;

    // Suche akzeptiert Barcode ODER ArtikelArtikelnummer
    public Artikel? GetByCode(string? input)
    {
        if (string.IsNullOrWhiteSpace(input)) return null;
        var key = Normalize(input);

        if (_indexBarcode.TryGetValue(key, out var id) && _byId.TryGetValue(id, out var a1))
            return a1;

        if (_indexArtikelnummer.TryGetValue(key, out id) && _byId.TryGetValue(id, out var a2))
            return a2;

        // optional: zusätzlich ohne führende Nullen probieren (kann Kollisionen erhöhen!)
        var noLeading = key.TrimStart('0');
        if (noLeading.Length > 0)
        {
            if (_indexBarcode.TryGetValue(noLeading, out id) && _byId.TryGetValue(id, out var a3))
                return a3;
            if (_indexArtikelnummer.TryGetValue(noLeading, out id) && _byId.TryGetValue(id, out var a4))
                return a4;
        }

        return null;
    }

    private static string Normalize(string s) => s.Trim();
}
