using Meezi.Core.Branding;
using Meezi.Core.Discover;
using Meezi.Core.Entities;
using Meezi.Core.Enums;
using Meezi.Infrastructure.Branding;
using Meezi.Infrastructure.Discover;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace Meezi.Infrastructure.Data;

public static class DevelopmentDataSeeder
{
    public static async Task SeedAsync(IServiceProvider services)
    {
        var env = services.GetRequiredService<IHostEnvironment>();
        if (!env.IsDevelopment())
            return;

        var logger = services.GetRequiredService<ILoggerFactory>().CreateLogger("DevelopmentDataSeeder");
        await using var scope = services.CreateAsyncScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();

        var cafe = await db.Cafes.FirstOrDefaultAsync(c => c.Slug == "demo-cafe");
        if (cafe is null)
        {
            cafe = new Cafe
            {
                Id = "cafe_demo_001",
                Name = "کافه دمو",
                NameEn = "Demo Cafe",
                Slug = "demo-cafe",
                City = "تهران",
                Address = "تهران، خیابان ولیعصر",
                Description = "کافه دمو میزی — مناسب کار، میهمانی و قهوه تخصصی.",
                PlanTier = PlanTier.Pro,
                PreferredLanguage = "fa",
                IsVerified = true,
                SnappfoodVendorId = "demo_vendor"
            };

            var owner = new Employee
            {
                Id = "emp_demo_owner",
                CafeId = cafe.Id,
                BranchId = "branch_demo_main",
                Name = "مدیر دمو",
                Phone = "09212273138",
                Role = EmployeeRole.Owner,
                BaseSalary = 0
            };

            db.Cafes.Add(cafe);
            db.Employees.Add(owner);
            await db.SaveChangesAsync();

            logger.LogInformation("Development seed: cafe slug={Slug}, owner phone={Phone}", cafe.Slug, owner.Phone);
        }
        else if (string.IsNullOrEmpty(cafe.SnappfoodVendorId))
        {
            cafe.SnappfoodVendorId = "demo_vendor";
            await db.SaveChangesAsync();
        }

        if (string.IsNullOrEmpty(cafe.ThemeJson))
        {
            cafe.ThemeJson = CafeThemeSerializer.Serialize(new CafeTheme
            {
                PaletteId = CafeThemeDefaults.PaletteMeeziGreen,
                PanelStyle = CafeThemeDefaults.PanelModern,
                MenuStyle = CafeThemeDefaults.MenuCards,
                Density = CafeThemeDefaults.DensityComfortable,
                Radius = CafeThemeDefaults.RadiusMd
            });
            await db.SaveChangesAsync();
        }

        if (string.IsNullOrEmpty(cafe.DiscoverProfileJson))
        {
            cafe.DiscoverProfileJson = CafeDiscoverProfileSerializer.Serialize(new CafeDiscoverProfile
            {
                Themes = ["modern", "plants_heavy"],
                Size = "cozy",
                Vibes = ["quiet", "cozy"],
                Occasions = ["date", "friends", "study_work"],
                SpaceFeatures = ["indoor", "wifi", "plants"],
                NoiseLevel = "quiet",
                PriceTier = "mid"
            });
            await db.SaveChangesAsync();
        }

        await SeedDemoReviewsAsync(db, cafe.Id, logger);
        await SeedDemoBranchAsync(db, cafe.Id, logger);
        await SeedDemoOpenShiftsAsync(db, cafe.Id, logger);

        var ownerEmp = await db.Employees.FirstOrDefaultAsync(e => e.Id == "emp_demo_owner");
        if (ownerEmp is not null)
        {
            var changed = false;
            if (ownerEmp.BranchId is null) { ownerEmp.BranchId = "branch_demo_main"; changed = true; }
            if (ownerEmp.Phone != "09212273138") { ownerEmp.Phone = "09212273138"; changed = true; }
            if (changed) await db.SaveChangesAsync();
        }

        await DemoEmployeesSeeder.EnsureEmployeesAsync(db, cafe.Id, logger);

        const string taxId = "tax_demo_vat";
        await DemoMenuSeeder.EnsureMenuAsync(db, cafe.Id, taxId, logger);
        await SeedDemoInventoryAsync(db, cafe.Id, logger);
        await DemoCouponSeeder.EnsureCouponsAsync(db, cafe.Id, logger);
        await SeedDemoTablesAsync(db, cafe.Id, logger);

        if (!await db.EmployeeSchedules.AnyAsync(s => s.EmployeeId == "emp_demo_owner"))
        {
        for (var day = 0; day <= 6; day++)
        {
            db.EmployeeSchedules.Add(new EmployeeSchedule
            {
                EmployeeId = "emp_demo_owner",
                DayOfWeek = day,
                ShiftType = day is 5 ? ShiftType.DayOff : ShiftType.Morning
            });
        }

        var monthYear = DateTime.UtcNow.ToString("yyyy-MM");
        db.EmployeeSalaries.Add(new EmployeeSalary
        {
            EmployeeId = "emp_demo_owner",
            MonthYear = monthYear,
            BaseSalary = 25_000_000,
            OvertimePay = 0,
            Deductions = 0,
            NetSalary = 25_000_000,
            IsPaid = false
        });

        await db.SaveChangesAsync();
        logger.LogInformation("Development HR seed for cafe {CafeId}", cafe.Id);
        }

        await SeedDemoOrdersAsync(db, cafe.Id, logger);
        await DiscoverShowcaseSeeder.SeedAsync(db, logger);
    }

    private static async Task SeedDemoBranchAsync(AppDbContext db, string cafeId, ILogger logger)
    {
        const string branchId = "branch_demo_main";
        if (!await db.Branches.AnyAsync(b => b.Id == branchId))
        {
            var now = DateTime.UtcNow;
            db.Branches.Add(new Branch
            {
                Id = branchId,
                CafeId = cafeId,
                Name = "شعبه اصلی",
                City = "تهران",
                Address = "تهران، خیابان ولیعصر",
                Phone = "02112345678",
                IsActive = true,
                CreatedAt = now,
                UpdatedAt = now
            });
            await db.SaveChangesAsync();
            logger.LogInformation("Development branch seed: {BranchId}", branchId);
        }
    }

    private static async Task SeedDemoOpenShiftsAsync(AppDbContext db, string cafeId, ILogger logger)
    {
        const string ownerId = "emp_demo_owner";
        var branchIds = await db.Branches
            .Where(b => b.CafeId == cafeId && b.IsActive)
            .Select(b => b.Id)
            .ToListAsync();

        var added = false;
        foreach (var branchId in branchIds)
        {
            var hasOpen = await db.RegisterShifts.AnyAsync(
                s => s.CafeId == cafeId && s.BranchId == branchId && s.Status == ShiftStatus.Open);
            if (hasOpen)
                continue;

            db.RegisterShifts.Add(new Shift
            {
                Id = $"shift_open_{branchId}",
                CafeId = cafeId,
                BranchId = branchId,
                OpenedByUserId = ownerId,
                OpenedAt = DateTime.UtcNow,
                OpeningCash = 0,
                ExpectedCash = 0,
                Status = ShiftStatus.Open
            });
            added = true;
        }

        if (added)
        {
            await db.SaveChangesAsync();
            logger.LogInformation("Development open-shift seed for cafe {CafeId}", cafeId);
        }
    }

    private static async Task SeedDemoInventoryAsync(AppDbContext db, string cafeId, ILogger logger)
    {
        if (await db.Ingredients.AnyAsync(i => i.CafeId == cafeId))
            return;

        db.Ingredients.AddRange(
            new Ingredient
            {
                Id = "ing_demo_milk",
                CafeId = cafeId,
                Name = "شیر",
                Unit = "میلی‌لیتر",
                QuantityOnHand = 12000,
                ReorderLevel = 2000,
                ParLevel = 12000,
                UnitCost = 80,
                LowStockWarningPercent = 20
            },
            new Ingredient
            {
                Id = "ing_demo_coffee",
                CafeId = cafeId,
                Name = "پودر قهوه",
                Unit = "گرم",
                QuantityOnHand = 500,
                ReorderLevel = 100,
                ParLevel = 500,
                UnitCost = 12,
                LowStockWarningPercent = 20
            },
            new Ingredient
            {
                Id = "ing_demo_cups",
                CafeId = cafeId,
                Name = "لیوان یکبارمصرف",
                Unit = "عدد",
                QuantityOnHand = 80,
                ReorderLevel = 20,
                ParLevel = 100,
                UnitCost = 500,
                LowStockWarningPercent = 20
            });

        await db.SaveChangesAsync();

        var espresso = await db.MenuItems
            .FirstOrDefaultAsync(m => m.CafeId == cafeId && m.Name.Contains("اسپرسو"));
        if (espresso is not null)
        {
            db.MenuItemIngredients.AddRange(
                new MenuItemIngredient
                {
                    Id = "mii_demo_espresso_coffee",
                    CafeId = cafeId,
                    MenuItemId = espresso.Id,
                    IngredientId = "ing_demo_coffee",
                    QuantityPerUnit = 10
                },
                new MenuItemIngredient
                {
                    Id = "mii_demo_espresso_cup",
                    CafeId = cafeId,
                    MenuItemId = espresso.Id,
                    IngredientId = "ing_demo_cups",
                    QuantityPerUnit = 1
                });
            await db.SaveChangesAsync();
        }
        logger.LogInformation("Development inventory seed for cafe {CafeId}", cafeId);
    }

    private static async Task SeedDemoTablesAsync(AppDbContext db, string cafeId, ILogger logger)
    {
        var specs = new (string Id, string Number, int Capacity, string? Floor, string? QrCode)[]
        {
            ("table_demo_1", "1", 4, "همکف", "demo_table_01"),
            ("table_demo_2", "2", 2, "همکف", null),
            ("table_demo_3", "3", 4, "همکف", null),
            ("table_demo_4", "4", 6, "بالکن", null),
            ("table_demo_5", "5", 4, "بالکن", null),
            ("table_demo_6", "6", 2, "بالکن", null),
            ("table_demo_7", "7", 8, "سالن VIP", null),
            ("table_demo_8", "8", 4, "سالن VIP", null),
        };

        foreach (var s in specs)
        {
            if (await db.Tables.AnyAsync(t => t.Id == s.Id))
                continue;

            db.Tables.Add(new Table
            {
                Id = s.Id,
                CafeId = cafeId,
                BranchId = "branch_demo_main",
                Number = s.Number,
                Capacity = s.Capacity,
                Floor = s.Floor,
                QrCode = s.QrCode ?? Guid.NewGuid().ToString("N"),
                IsActive = true
            });
        }

        await db.SaveChangesAsync();
        logger.LogInformation("Development tables seed (8 tables, QR: demo_table_01) for cafe {CafeId}", cafeId);
    }

    private static async Task SeedDemoReviewsAsync(AppDbContext db, string cafeId, ILogger logger)
    {
        if (await db.CafeReviews.AnyAsync(r => r.CafeId == cafeId))
            return;

        db.CafeReviews.AddRange(
            new CafeReview
            {
                CafeId = cafeId,
                AuthorName = "سارا",
                Rating = 5,
                Comment = "قهوه و فضا عالی بود.",
                CreatedAt = DateTime.UtcNow.AddDays(-3)
            },
            new CafeReview
            {
                CafeId = cafeId,
                AuthorName = "علی",
                Rating = 4,
                Comment = "سرویس سریع، کیک خوشمزه.",
                CreatedAt = DateTime.UtcNow.AddDays(-1)
            });

        await db.SaveChangesAsync();
        logger.LogInformation("Development reviews seed for cafe {CafeId}", cafeId);
    }

    private static async Task SeedDemoOrdersAsync(AppDbContext db, string cafeId, ILogger logger)
    {
        if (await db.Orders.AnyAsync(o => o.CafeId == cafeId))
            return;

        var latte = await db.MenuItems.FirstOrDefaultAsync(m => m.Id == "item_demo_latte");
        var cake = await db.MenuItems.FirstOrDefaultAsync(m => m.Id == "item_demo_cake");
        if (latte is null || cake is null)
            return;

        var customer = new Customer
        {
            Id = "cust_demo_reports",
            CafeId = cafeId,
            Name = "مشتری گزارش",
            Phone = "09120000001",
            Group = CustomerGroup.Regular,
            CreatedAt = DateTime.UtcNow.AddDays(-10)
        };
        db.Customers.Add(customer);

        for (var i = 0; i < 7; i++)
        {
            var createdAt = DateTime.UtcNow.AddDays(-i).AddHours(-2);
            var subtotal = 215_000m;
            var tax = Math.Round(subtotal * 0.09m, 0);
            var order = new Order
            {
                Id = $"order_demo_{i}",
                CafeId = cafeId,
                CustomerId = i % 2 == 0 ? customer.Id : null,
                OrderType = OrderType.DineIn,
                Status = OrderStatus.Delivered,
                DisplayNumber = i + 1,
                Subtotal = subtotal,
                TaxTotal = tax,
                DiscountAmount = i == 0 ? 15_000m : 0,
                Total = subtotal + tax - (i == 0 ? 15_000m : 0),
                CreatedAt = createdAt
            };
            db.Orders.Add(order);
            db.OrderItems.AddRange(
                new OrderItem
                {
                    OrderId = order.Id,
                    MenuItemId = latte.Id,
                    Quantity = 1,
                    UnitPrice = latte.Price
                },
                new OrderItem
                {
                    OrderId = order.Id,
                    MenuItemId = cake.Id,
                    Quantity = 1,
                    UnitPrice = cake.Price
                });
        }

        await db.SaveChangesAsync();
        logger.LogInformation("Development reports seed: 7 demo orders for cafe {CafeId}", cafeId);
    }
}
