using foodmarket.Domain.Catalog;
using foodmarket.Infrastructure.Persistence;
using Microsoft.EntityFrameworkCore;

namespace foodmarket.Api.Seed;

// Populates a starter catalog so the system is usable immediately after first run.
// Runs only in Development and only if the tenant has no products yet — safe to run multiple times.
public class DemoCatalogSeeder : IHostedService
{
    private readonly IServiceProvider _services;
    private readonly IHostEnvironment _env;

    public DemoCatalogSeeder(IServiceProvider services, IHostEnvironment env)
    {
        _services = services;
        _env = env;
    }

    public async Task StartAsync(CancellationToken ct)
    {
        if (!_env.IsDevelopment()) return;

        using var scope = _services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();

        var demoOrg = await db.Organizations.FirstOrDefaultAsync(o => o.Name == "Demo Market", ct);
        if (demoOrg is null) return;
        var orgId = demoOrg.Id;

        // Skip if products already present — don't re-seed on every restart.
        var hasProducts = await db.Products.IgnoreQueryFilters().AnyAsync(p => p.OrganizationId == orgId, ct);
        if (hasProducts) return;

        // KZ дефолт — 16% (из Country.VatRate), льготные категории (хлеб) — 0%.
        const decimal vatDefault = 16m;
        const decimal vat0 = 0m;

        // Phase5c: единицы измерения — глобальные (OrganizationId IS NULL).
        var unitSht = await db.UnitsOfMeasure.IgnoreQueryFilters()
            .FirstOrDefaultAsync(u => u.OrganizationId == null && u.Code == "796", ct);
        var unitKg = await db.UnitsOfMeasure.IgnoreQueryFilters()
            .FirstOrDefaultAsync(u => u.OrganizationId == null && u.Code == "166", ct);
        var unitL = await db.UnitsOfMeasure.IgnoreQueryFilters()
            .FirstOrDefaultAsync(u => u.OrganizationId == null && u.Code == "112", ct);

        if (unitSht is null) return;

        var retailPriceType = await db.PriceTypes.IgnoreQueryFilters()
            .FirstOrDefaultAsync(p => p.OrganizationId == orgId && p.IsRetail, ct);
        if (retailPriceType is null) return;

        var kzt = await db.Currencies.FirstOrDefaultAsync(c => c.Code == "KZT", ct);
        if (kzt is null) return;

        var kz = await db.Countries.FirstOrDefaultAsync(c => c.Code == "KZ", ct);
        var ru = await db.Countries.FirstOrDefaultAsync(c => c.Code == "RU", ct);

        // Product groups (hierarchy — Напитки/Безалкогольные, Напитки/Алкогольные, etc.)
        var groups = new Dictionary<string, Guid>();
        Guid AddGroup(string name, Guid? parentId)
        {
            var id = Guid.NewGuid();
            var path = parentId is null
                ? name
                : $"{groups.First(g => g.Value == parentId).Key}/{name}";
            db.ProductGroups.Add(new ProductGroup
            {
                Id = id, OrganizationId = orgId, Name = name, ParentId = parentId,
            });
            groups[path] = id;
            return id;
        }

        // «Продукты питания» — дефолтная группа, в которую попадают новые товары,
        // если пользователь не указал группу явно. Не должна удаляться.
        AddGroup("Продукты питания", null);
        var gDrinks = AddGroup("Напитки", null);
        var gDrinksNon = AddGroup("Безалкогольные", gDrinks);
        AddGroup("Алкогольные", gDrinks);
        var gDairy = AddGroup("Молочные продукты", null);
        var gBakery = AddGroup("Хлеб и выпечка", null);
        var gSweets = AddGroup("Кондитерские", null);
        var gGrocery = AddGroup("Бакалея", null);
        var gSnacks = AddGroup("Снеки", null);

        // Demo suppliers
        var supplier1 = new Counterparty
        {
            OrganizationId = orgId, Name = "ТОО «Продтрейд»", LegalName = "Товарищество с ограниченной ответственностью «Продтрейд»",
            Type = CounterpartyType.LegalEntity,
            Bin = "100140005678", CountryId = kz?.Id,
            Address = "Алматы, ул. Абая 15", Phone = "+7 (727) 100-00-01",
            Email = "order@prodtrade.kz", BankName = "Kaspi Bank", BankAccount = "KZ000000000000000001", Bik = "CASPKZKA",
        };
        var supplier2 = new Counterparty
        {
            OrganizationId = orgId, Name = "ИП Иванов А.С.",
            Type = CounterpartyType.Individual,
            Iin = "850101300000", CountryId = kz?.Id,
            Phone = "+7 (777) 100-00-02", ContactPerson = "Иванов Алексей",
        };
        db.Counterparties.AddRange(supplier1, supplier2);

        // Barcodes use generic internal range (2xxxxxxxxxxxx) to avoid colliding with real products.
        // When user does real приёмка, real barcodes will overwrite.
        var demo = new (string Name, Guid Group, decimal RetailPrice, string Article, string Barcode, Guid? Country, bool IsWeighed, Guid Unit)[]
        {
            // Напитки — безалкогольные
            ("Вода питьевая «Тассай» 0.5л", gDrinksNon, 220, "DR-WAT-001", "2000000000018", kz?.Id, false, unitSht.Id),
            ("Вода питьевая «Тассай» 1.5л", gDrinksNon, 380, "DR-WAT-002", "2000000000025", kz?.Id, false, unitSht.Id),
            ("Сок «Да-Да» яблоко 1л", gDrinksNon, 650, "DR-JUC-001", "2000000000032", kz?.Id, false, unitSht.Id),
            ("Сок «Да-Да» апельсин 1л", gDrinksNon, 650, "DR-JUC-002", "2000000000049", kz?.Id, false, unitSht.Id),
            ("Кока-кола 0.5л", gDrinksNon, 420, "DR-SOD-001", "2000000000056", ru?.Id, false, unitSht.Id),
            ("Пепси 0.5л", gDrinksNon, 420, "DR-SOD-002", "2000000000063", ru?.Id, false, unitSht.Id),
            ("Спрайт 0.5л", gDrinksNon, 420, "DR-SOD-003", "2000000000070", ru?.Id, false, unitSht.Id),
            ("Чай чёрный «Пиала» пакетированный, 100шт", gDrinksNon, 1250, "DR-TEA-001", "2000000000087", kz?.Id, false, unitSht.Id),
            // Молочные
            ("Молоко «Простоквашино» 2.5% 930мл", gDairy, 720, "DAI-MLK-001", "2000000000094", ru?.Id, false, unitSht.Id),
            ("Молоко «Food Master» 3.2% 1л", gDairy, 620, "DAI-MLK-002", "2000000000100", kz?.Id, false, unitSht.Id),
            ("Кефир «Food Master» 2.5% 1л", gDairy, 590, "DAI-KEF-001", "2000000000117", kz?.Id, false, unitSht.Id),
            ("Йогурт «Актимель» клубника 100мл", gDairy, 180, "DAI-YOG-001", "2000000000124", null, false, unitSht.Id),
            ("Творог «Простоквашино» 5% 200г", gDairy, 590, "DAI-CRD-001", "2000000000131", ru?.Id, false, unitSht.Id),
            ("Сметана «Food Master» 20% 400г", gDairy, 850, "DAI-SCR-001", "2000000000148", kz?.Id, false, unitSht.Id),
            ("Сыр «Российский» 45%", gDairy, 3200, "DAI-CHE-001", "2000000000155", kz?.Id, true, unitKg?.Id ?? unitSht.Id),
            // Хлеб и выпечка
            ("Хлеб «Семейный» нарезной 500г", gBakery, 180, "BAK-BRD-001", "2000000000162", kz?.Id, false, unitSht.Id),
            ("Батон «Столичный» 400г", gBakery, 170, "BAK-BRD-002", "2000000000179", kz?.Id, false, unitSht.Id),
            ("Лепёшка домашняя", gBakery, 220, "BAK-LEP-001", "2000000000186", kz?.Id, false, unitSht.Id),
            ("Круассан шоколадный", gBakery, 320, "BAK-CRO-001", "2000000000193", kz?.Id, false, unitSht.Id),
            // Кондитерские
            ("Шоколад «Рахат» молочный 100г", gSweets, 650, "SW-CHO-001", "2000000000209", kz?.Id, false, unitSht.Id),
            ("Шоколад «Алёнка» 100г", gSweets, 620, "SW-CHO-002", "2000000000216", ru?.Id, false, unitSht.Id),
            ("Конфеты «Казахстанские» 200г", gSweets, 890, "SW-CND-001", "2000000000223", kz?.Id, false, unitSht.Id),
            ("Печенье «Юбилейное» 250г", gSweets, 540, "SW-CKE-001", "2000000000230", ru?.Id, false, unitSht.Id),
            ("Вафли «Артек» 250г", gSweets, 480, "SW-WAF-001", "2000000000247", kz?.Id, false, unitSht.Id),
            // Бакалея
            ("Сахар-песок 1кг", gGrocery, 480, "GRO-SUG-001", "2000000000254", kz?.Id, false, unitSht.Id),
            ("Соль поваренная 1кг", gGrocery, 180, "GRO-SLT-001", "2000000000261", kz?.Id, false, unitSht.Id),
            ("Рис круглозёрный 1кг", gGrocery, 850, "GRO-RCE-001", "2000000000278", kz?.Id, false, unitSht.Id),
            ("Гречка «Мистраль» 900г", gGrocery, 990, "GRO-GRE-001", "2000000000285", ru?.Id, false, unitSht.Id),
            ("Макароны «Corona» 500г", gGrocery, 420, "GRO-PAS-001", "2000000000292", kz?.Id, false, unitSht.Id),
            ("Масло подсолнечное «Шедевр» 1л", gGrocery, 920, "GRO-OIL-001", "2000000000308", kz?.Id, false, unitL?.Id ?? unitSht.Id),
            ("Кофе «Якобс Монарх» 95г растворимый", gGrocery, 2890, "GRO-COF-001", "2000000000315", null, false, unitSht.Id),
            // Снеки
            ("Чипсы «Lays» сметана-лук 80г", gSnacks, 380, "SN-CHP-001", "2000000000322", kz?.Id, false, unitSht.Id),
            ("Сухарики «3 корочки» ржаные 40г", gSnacks, 190, "SN-SBR-001", "2000000000339", ru?.Id, false, unitSht.Id),
            ("Орешки фисташки 100г", gSnacks, 1190, "SN-NUT-001", "2000000000346", kz?.Id, false, unitSht.Id),
            ("Семечки «Мартин» 100г", gSnacks, 290, "SN-SED-001", "2000000000353", ru?.Id, false, unitSht.Id),
        };

        var products = demo.Select(d =>
        {
            var p = new Product
            {
                OrganizationId = orgId,
                Name = d.Name,
                Article = d.Article,
                UnitOfMeasureId = d.Unit,
                // Хлеб/батон/лепёшка — 0% (льготная категория в KZ).
                Vat = d.Name.Contains("Хлеб") || d.Name.Contains("Батон") || d.Name.Contains("Лепёшка")
                    ? vat0 : vatDefault,
                VatEnabled = !(d.Name.Contains("Хлеб") || d.Name.Contains("Батон") || d.Name.Contains("Лепёшка")),
                ProductGroupId = d.Group,
                CountryOfOriginId = d.Country,
                Packaging = d.IsWeighed ? Packaging.Weight : Packaging.Piece,
                ReferencePrice = Math.Round(d.RetailPrice * 0.72m, 2),
                PurchaseCurrencyId = kzt.Id,
                Prices =
                [
                    new ProductPrice
                    {
                        OrganizationId = orgId,
                        PriceTypeId = retailPriceType.Id,
                        Amount = d.RetailPrice,
                        CurrencyId = kzt.Id,
                    },
                ],
                Barcodes =
                [
                    new ProductBarcode
                    {
                        OrganizationId = orgId,
                        Code = d.Barcode,
                        Type = BarcodeType.Ean13,
                        IsPrimary = true,
                    },
                ],
            };
            return p;
        }).ToList();

        db.Products.AddRange(products);
        await db.SaveChangesAsync(ct);
    }

    public Task StopAsync(CancellationToken ct) => Task.CompletedTask;
}
