using Microsoft.EntityFrameworkCore;
using PowderCoating.Core.Entities;
using PowderCoating.Core.Enums;

namespace PowderCoating.Infrastructure.Services;

public partial class SeedDataService
{
    /// <summary>
    /// Seeds 7 purchase orders across three vendors covering a 3-month window:
    /// 3 Received (historical), 2 Submitted (in-flight), and 2 Draft (pending approval).
    /// This gives every PO status a visible example for demo walkthroughs.
    /// </summary>
    /// <remarks>
    /// Vendors are resolved by partial name match against the company's vendor list — the
    /// same approach used by <see cref="SeedBillsAsync"/>. PO numbers follow the convention
    /// <c>PO-YYMM-####</c> stamped at seed time.
    ///
    /// Received POs link back to the <see cref="Bill"/> that was created after receipt when
    /// one with a matching vendor invoice number exists; otherwise <c>BillId</c> is left null
    /// so the PO still seeds cleanly even if bills were skipped.
    ///
    /// Idempotency: returns 0 immediately if any purchase orders already exist for the company.
    /// </remarks>
    /// <param name="company">The tenant company to seed purchase orders for.</param>
    /// <returns>Number of PO records inserted, or 0 if already seeded.</returns>
    private async Task<int> SeedPurchaseOrdersAsync(Company company)
    {
        var existingCount = await _context.Set<PurchaseOrder>()
            .IgnoreQueryFilters()
            .CountAsync(p => p.CompanyId == company.Id && !p.IsDeleted);

        if (existingCount > 0)
            return 0;

        var vendors = await _context.Set<Vendor>()
            .IgnoreQueryFilters()
            .Where(v => v.CompanyId == company.Id && !v.IsDeleted)
            .ToListAsync();

        if (vendors.Count == 0)
            return 0;

        var prismatic   = vendors.FirstOrDefault(v => v.CompanyName.Contains("Prismatic"))  ?? vendors.First();
        var columbia    = vendors.FirstOrDefault(v => v.CompanyName.Contains("Columbia"))   ?? vendors.First();
        var harbor      = vendors.FirstOrDefault(v => v.CompanyName.Contains("Harbor"))     ?? vendors.First();
        var grainger    = vendors.FirstOrDefault(v => v.CompanyName.Contains("Grainger"))   ?? vendors.First();
        var localSupply = vendors.FirstOrDefault(v => v.CompanyName.Contains("Local"))      ?? vendors.First();

        // Resolve inventory item IDs for PO line items (optional — may be null if inventory
        // wasn't seeded yet; the PO seeds cleanly either way using the Description field).
        var glossBlack  = await _context.Set<InventoryItem>().IgnoreQueryFilters()
            .FirstOrDefaultAsync(i => i.CompanyId == company.Id && i.SKU.EndsWith("-PWD-GBK-001") && !i.IsDeleted);
        var matteBlack  = await _context.Set<InventoryItem>().IgnoreQueryFilters()
            .FirstOrDefaultAsync(i => i.CompanyId == company.Id && i.SKU.EndsWith("-PWD-MBK-001") && !i.IsDeleted);
        var superChrome = await _context.Set<InventoryItem>().IgnoreQueryFilters()
            .FirstOrDefaultAsync(i => i.CompanyId == company.Id && i.SKU.EndsWith("-PWD-CHR-001") && !i.IsDeleted);
        var candyRed    = await _context.Set<InventoryItem>().IgnoreQueryFilters()
            .FirstOrDefaultAsync(i => i.CompanyId == company.Id && i.SKU.EndsWith("-PWD-CRD-001") && !i.IsDeleted);
        var blastMedia  = await _context.Set<InventoryItem>().IgnoreQueryFilters()
            .FirstOrDefaultAsync(i => i.CompanyId == company.Id && i.SKU.EndsWith("-BLM-001") && !i.IsDeleted);

        var now    = DateTime.UtcNow;
        var pfx    = $"PO-{now:yy}{now.Month:D2}-";
        var seq    = 1;
        var seeded = 0;

        async Task<PurchaseOrder> AddPO(PurchaseOrder po)
        {
            po.PoNumber   = $"{pfx}{seq++:D4}";
            po.CompanyId  = company.Id;
            foreach (var item in po.Items)
            {
                item.CompanyId = company.Id;
                item.CreatedAt = po.OrderDate;
            }
            await _context.Set<PurchaseOrder>().AddAsync(po);
            await _context.SaveChangesAsync();
            seeded++;
            return po;
        }

        // ── RECEIVED (historical — tied to bills already in the system) ───────

        // PO-1: Prismatic Powders — powder restock 3 months ago (Received, matches bill PP-77211)
        await AddPO(new PurchaseOrder
        {
            VendorId             = prismatic.Id,
            Status               = PurchaseOrderStatus.Received,
            OrderDate            = now.AddDays(-95),
            ExpectedDeliveryDate = now.AddDays(-80),
            ReceivedDate         = now.AddDays(-82),
            SubTotal             = 1_145.00m,
            TotalAmount          = 1_145.00m,
            Notes                = "Quarterly powder restock — Q1",
            CreatedAt            = now.AddDays(-95),
            Items =
            {
                new PurchaseOrderItem { InventoryItemId = matteBlack?.Id,  Description = "Matte Black Powder — 50 lb bags",  UnitOfMeasure = "bag", QuantityOrdered = 2, QuantityReceived = 2, UnitCost = 178.00m, LineTotal = 356.00m },
                new PurchaseOrderItem { InventoryItemId = glossBlack?.Id,  Description = "Gloss Black Powder — 50 lb bags",  UnitOfMeasure = "bag", QuantityOrdered = 2, QuantityReceived = 2, UnitCost = 165.00m, LineTotal = 330.00m },
                new PurchaseOrderItem { Description = "Satin Silver Powder — 25 lb bags", UnitOfMeasure = "bag", QuantityOrdered = 2, QuantityReceived = 2, UnitCost = 144.50m, LineTotal = 289.00m },
                new PurchaseOrderItem { Description = "Masking Tape & Plugs Kit",          UnitOfMeasure = "kit", QuantityOrdered = 1, QuantityReceived = 1, UnitCost = 170.00m, LineTotal = 170.00m }
            }
        });

        // PO-2: Columbia Coatings — specialty colors 2 months ago (Received, matches bill CC-4401)
        await AddPO(new PurchaseOrder
        {
            VendorId             = columbia.Id,
            Status               = PurchaseOrderStatus.Received,
            OrderDate            = now.AddDays(-70),
            ExpectedDeliveryDate = now.AddDays(-58),
            ReceivedDate         = now.AddDays(-60),
            SubTotal             = 986.00m,
            TotalAmount          = 986.00m,
            Notes                = "Specialty metallic & candy colors order",
            CreatedAt            = now.AddDays(-70),
            Items =
            {
                new PurchaseOrderItem { InventoryItemId = candyRed?.Id,    Description = "Candy Red Metallic — 10 lb bags",  UnitOfMeasure = "bag", QuantityOrdered = 3, QuantityReceived = 3, UnitCost = 145.00m, LineTotal = 435.00m },
                new PurchaseOrderItem { InventoryItemId = superChrome?.Id, Description = "Chrome Effect Powder — 10 lb bags", UnitOfMeasure = "bag", QuantityOrdered = 2, QuantityReceived = 2, UnitCost = 168.00m, LineTotal = 336.00m },
                new PurchaseOrderItem { Description = "Hammertone Bronze — 10 lb bags",   UnitOfMeasure = "bag", QuantityOrdered = 1, QuantityReceived = 1, UnitCost = 150.50m, LineTotal = 150.50m },
                new PurchaseOrderItem { Description = "Ground Straps & Hooks",             UnitOfMeasure = "lot", QuantityOrdered = 1, QuantityReceived = 1, UnitCost =  64.50m, LineTotal =  64.50m }
            }
        });

        // PO-3: Harbor Freight Tools — consumables 6 weeks ago (Received, matches bill HBF-18822 timing)
        await AddPO(new PurchaseOrder
        {
            VendorId             = harbor.Id,
            Status               = PurchaseOrderStatus.Received,
            OrderDate            = now.AddDays(-48),
            ExpectedDeliveryDate = now.AddDays(-40),
            ReceivedDate         = now.AddDays(-42),
            SubTotal             = 412.50m,
            TotalAmount          = 412.50m,
            Notes                = "Shop consumables & hardware restock",
            CreatedAt            = now.AddDays(-48),
            Items =
            {
                new PurchaseOrderItem { Description = "J-Hook Hangers Assortment",         UnitOfMeasure = "pkg", QuantityOrdered = 2, QuantityReceived = 2, UnitCost =  89.75m, LineTotal = 179.50m },
                new PurchaseOrderItem { Description = "Masking Caps — Mixed (100-pack)",    UnitOfMeasure = "box", QuantityOrdered = 2, QuantityReceived = 2, UnitCost =  60.00m, LineTotal = 120.00m },
                new PurchaseOrderItem { Description = "Wire Brushes & Abrasives",           UnitOfMeasure = "lot", QuantityOrdered = 1, QuantityReceived = 1, UnitCost = 113.00m, LineTotal = 113.00m }
            }
        });

        // ── SUBMITTED (in-flight — awaiting delivery) ─────────────────────────

        // PO-4: Grainger Industrial Supply — safety equipment & filter replacement (matches open GRG-7714 partial bill)
        await AddPO(new PurchaseOrder
        {
            VendorId             = grainger.Id,
            Status               = PurchaseOrderStatus.Submitted,
            OrderDate            = now.AddDays(-14),
            ExpectedDeliveryDate = now.AddDays(3),
            SubTotal             = 648.00m,
            TotalAmount          = 648.00m,
            Notes                = "Blast room filter replacement + safety restocking",
            CreatedAt            = now.AddDays(-14),
            Items =
            {
                new PurchaseOrderItem { Description = "HEPA Filter Cartridges — 12-pack",  UnitOfMeasure = "box", QuantityOrdered = 2, QuantityReceived = 0, UnitCost = 189.00m, LineTotal = 378.00m },
                new PurchaseOrderItem { Description = "Blast Nozzle Tungsten — 3/8\"",     UnitOfMeasure = "ea",  QuantityOrdered = 2, QuantityReceived = 0, UnitCost =  85.00m, LineTotal = 170.00m },
                new PurchaseOrderItem { Description = "Safety Respirators (10-pack)",       UnitOfMeasure = "box", QuantityOrdered = 1, QuantityReceived = 0, UnitCost = 100.00m, LineTotal = 100.00m }
            }
        });

        // PO-5: Prismatic Powders — current month powder order (matches open bill PP-88530)
        await AddPO(new PurchaseOrder
        {
            VendorId             = prismatic.Id,
            Status               = PurchaseOrderStatus.Submitted,
            OrderDate            = now.AddDays(-8),
            ExpectedDeliveryDate = now.AddDays(7),
            SubTotal             = 1_050.00m,
            TotalAmount          = 1_050.00m,
            Notes                = "June powder restock — Matte Black + seasonal Gloss Red",
            CreatedAt            = now.AddDays(-8),
            Items =
            {
                new PurchaseOrderItem { InventoryItemId = matteBlack?.Id,  Description = "Matte Black Powder — 25 lb bags",  UnitOfMeasure = "bag", QuantityOrdered = 6, QuantityReceived = 0, UnitCost =  89.00m, LineTotal = 534.00m },
                new PurchaseOrderItem { Description = "Gloss Red Powder — 10 lb bags",   UnitOfMeasure = "bag", QuantityOrdered = 2, QuantityReceived = 0, UnitCost = 132.00m, LineTotal = 264.00m },
                new PurchaseOrderItem { Description = "Hanging Racks (10-pack)",          UnitOfMeasure = "pkg", QuantityOrdered = 2, QuantityReceived = 0, UnitCost = 126.00m, LineTotal = 252.00m }
            }
        });

        // ── DRAFT (pending review / approval) ─────────────────────────────────

        // PO-6: Harbor Freight Tools — shop tools pending manager approval
        await AddPO(new PurchaseOrder
        {
            VendorId             = harbor.Id,
            Status               = PurchaseOrderStatus.Draft,
            OrderDate            = now.AddDays(-3),
            ExpectedDeliveryDate = now.AddDays(10),
            SubTotal             = 318.75m,
            TotalAmount          = 318.75m,
            Notes                = "Monthly hardware restock — needs approval before submit",
            InternalNotes        = "Manager review requested: higher than normal month due to extra hooks for upcoming Apex Motorsports batch.",
            CreatedAt            = now.AddDays(-3),
            Items =
            {
                new PurchaseOrderItem { Description = "Hanging Racks & J-Hooks",          UnitOfMeasure = "pkg", QuantityOrdered = 1, QuantityReceived = 0, UnitCost = 198.75m, LineTotal = 198.75m },
                new PurchaseOrderItem { Description = "Masking Caps — Mixed (100-pack)",   UnitOfMeasure = "box", QuantityOrdered = 2, QuantityReceived = 0, UnitCost =  60.00m, LineTotal = 120.00m }
            }
        });

        // PO-7: Local Industrial Supply — blast media restock (inventory currently at zero)
        await AddPO(new PurchaseOrder
        {
            VendorId             = localSupply.Id,
            Status               = PurchaseOrderStatus.Draft,
            OrderDate            = now.AddDays(-1),
            ExpectedDeliveryDate = now.AddDays(5),
            SubTotal             = 385.00m,
            TotalAmount          = 385.00m,
            Notes                = "URGENT — blast media out of stock, production blocked on Pressure Pot Blaster",
            InternalNotes        = "Rush order requested; call LIS rep for same-week delivery.",
            CreatedAt            = now.AddDays(-1),
            Items =
            {
                new PurchaseOrderItem { InventoryItemId = blastMedia?.Id, Description = "Aluminum Oxide #80 Grit — 100 lb bag", UnitOfMeasure = "bag", QuantityOrdered = 5, QuantityReceived = 0, UnitCost = 77.00m, LineTotal = 385.00m }
            }
        });

        return seeded;
    }
}
