using ERPCore.Domain.Entities;
using ERPCore.Domain;
using ERPCore.Domain.Enums;
using Microsoft.EntityFrameworkCore;

namespace ERPCore.Infra.Persistence;

/// <summary>
/// Idempotent startup seeding of configurable reference data (docs/10 §B.8.3).
/// Reason codes are seeded at runtime (not via <c>HasData</c>) so the identity
/// sequence advances normally and later admin <c>POST /reason-codes</c> calls
/// cannot collide with seeded ids.
/// </summary>
public static class DataSeeder
{
    /// <summary>
    /// Item type names the frontend builder has always assumed exist (they were hardcoded
    /// while it ran on mock data). Seeded so the dropdown is not empty on a fresh database;
    /// users add their own (e.g. Material) from the admin screen.
    /// </summary>
    private static readonly string[] StandardItemTypes = ["Color", "Size"];

    private static readonly (string Code, string Description, ReasonContext Context)[] StandardReasonCodes =
    [
        ("DMG", "Damage", ReasonContext.Adjustment),
        ("THEFT", "Theft/Loss", ReasonContext.Adjustment),
        ("VAR", "Count Variance", ReasonContext.Adjustment),
        ("EXP", "Expiry Write-off", ReasonContext.Adjustment),
        ("SYS", "System Correction", ReasonContext.Adjustment),
        ("DEF", "Defective", ReasonContext.Return),
        ("WRONG", "Wrong Item", ReasonContext.Return),
        ("OVER", "Over-supply", ReasonContext.Return),
        ("QREJ", "Quality Reject", ReasonContext.Return),
        // Manufacturing (docs/30 §A.2) — scrap at stage complete, leftover return before
        // receipt, and the mandatory reason on a run cancel.
        ("PRD-SCRAP", "Production Scrap", ReasonContext.Production),
        ("PRD-LEFTOVER", "Production Leftover Return", ReasonContext.Production),
        ("PRD-CANCEL", "Production Run Cancelled", ReasonContext.Production),
        ("PRD-REWORK-LOSS", "Production Rework Loss", ReasonContext.Production),
    ];

    public static async Task SeedAsync(ErpDbContext db, CancellationToken ct = default)
    {
        var dirty = await SeedReasonCodesAsync(db, ct);
        dirty |= await SeedItemTypesAsync(db, ct);
       // dirty |= await SeedCompanyProfileAsync(db, ct);
        dirty |= await SeedProductConfigAsync(db, ct);
        dirty |= await SeedSalesMastersAsync(db, ct);
        dirty |= await SeedSalesStockAsync(db, ct);
        dirty |= await SeedSalesAsync(db, ct);

        if (dirty) await db.SaveChangesAsync(ct);
    }

    private static async Task<bool> SeedReasonCodesAsync(ErpDbContext db, CancellationToken ct)
    {
        var existing = await db.ReasonCodes
            .Select(r => new { r.Context, r.Code })
            .ToListAsync(ct);
        var have = existing.Select(x => (x.Context, x.Code)).ToHashSet();

        var toAdd = StandardReasonCodes
            .Where(r => !have.Contains((r.Context, r.Code)))
            .Select(r => new ReasonCode { Code = r.Code, Description = r.Description, Context = r.Context })
            .ToList();

        if (toAdd.Count == 0) return false;

        db.ReasonCodes.AddRange(toAdd);
        return true;
    }

    private static async Task<bool> SeedItemTypesAsync(ErpDbContext db, CancellationToken ct)
    {
        var have = await db.ItemTypes.Select(t => t.Name).ToListAsync(ct);

        var toAdd = StandardItemTypes
            .Where(name => !have.Contains(name, StringComparer.OrdinalIgnoreCase))
            .Select(name => new ItemType { Name = name, Status = EntityStatus.Active, CreatedAt = DateTime.UtcNow })
            .ToList();

        if (toAdd.Count == 0) return false;

        db.ItemTypes.AddRange(toAdd);
        return true;
    }

    /// <summary>
    /// Ensures the singleton product-config row exists (FR-MD-11). Migration #2 inserts it,
    /// so this only fires for a database built some other way — but without it every Item
    /// write would 404 on the missing config, so it is worth the one query at startup.
    /// New deployments start with all features on.
    /// </summary>
    private static async Task<bool> SeedProductConfigAsync(ErpDbContext db, CancellationToken ct)
    {
        if (await db.ProductConfig.AnyAsync(c => c.ConfigId == ProductConfig.SingletonId, ct)) return false;

        db.ProductConfig.Add(new ProductConfig
        {
            ConfigId = ProductConfig.SingletonId,
            SubcategoriesEnabled = true,
            BrandsEnabled = true,
            ItemTypesEnabled = true
        });
        return true;
    }

    /// <summary>
    /// Seeds a printable company profile with reasonable defaults for invoice headers.
    /// These values are intentionally editable later through the API.
    /// </summary>
    //private static async Task<bool> SeedCompanyProfileAsync(ErpDbContext db, CancellationToken ct)
    //{
    //    if (await db.CompanyProfiles.AnyAsync(c => c.CompanyProfileId == CompanyProfile.SingletonId, ct)) return false;

    //    db.CompanyProfiles.Add(new CompanyProfile
    //    {
    //        CompanyProfileId = CompanyProfile.SingletonId,
    //        LegalName = "ERP Core Trading (Pvt) Ltd",
    //        TradeName = "ERP Core Trading",
    //        TaxRegistrationNo = "TAX-DEFAULT-001",
    //        VatRegistrationNo = "VAT-DEFAULT-001",
    //        AddressLine1 = "1 Demo Street",
    //        City = "Colombo",
    //        Country = "Sri Lanka",
    //        Phone = "+94 11 000 0000",
    //        Email = "accounts@example.com",
    //        BankName = "Demo Bank",
    //        BankBranch = "Colombo Main",
    //        AccountName = "ERP Core Trading (Pvt) Ltd",
    //        AccountNumber = "000123456789",
    //        SwiftCode = "DEMO1234",
    //        FooterNote = "Thank you for your business."
    //    });
    //    return true;
    //}

    /// <summary>
    /// Seeds the minimum catalog data required for the sales demo rows to exist.
    /// These are safe additive rows and do not alter any existing data.
    /// </summary>
    private static async Task<bool> SeedSalesMastersAsync(ErpDbContext db, CancellationToken ct)
    {
        var dirty = false;

        dirty |= await SeedWarehousesAsync(db, ct);
        dirty |= await SeedUomsAsync(db, ct);
        dirty |= await SeedCategoriesAsync(db, ct);
        dirty |= await SeedItemsAsync(db, ct);

        return dirty;
    }

    /// <summary>
    /// Seeds a simple on-hand FIFO layer for the demo sales item so the sample
    /// invoices can be posted without immediately failing stock validation.
    /// This keeps the stock-check and posting flows testable on a fresh database.
    /// </summary>
    private static async Task<bool> SeedSalesStockAsync(ErpDbContext db, CancellationToken ct)
    {
        var warehouse = await db.Warehouses.AsNoTracking()
            .OrderBy(w => w.WarehouseId)
            .FirstOrDefaultAsync(ct);
        var item = await db.Items.AsNoTracking()
            .OrderBy(i => i.ItemId)
            .FirstOrDefaultAsync(ct);
        var secondItem = await db.Items.AsNoTracking()
            .OrderByDescending(i => i.ItemId)
            .FirstOrDefaultAsync(ct);

        if (warehouse is null || item is null || secondItem is null)
            return false;

        var existing = await db.StockLayers.AnyAsync(
            l => (l.ItemId == item.ItemId || l.ItemId == secondItem.ItemId) && l.WarehouseId == warehouse.WarehouseId && l.QtyRemaining > 0m,
            ct);
        if (existing) return false;

        db.StockLayers.Add(new StockLayer
        {
            ItemId = item.ItemId,
            WarehouseId = warehouse.WarehouseId,
            QtyReceived = 100m,
            QtyRemaining = 100m,
            UnitCost = item.SalePrice.GetValueOrDefault() > 0m ? item.SalePrice.GetValueOrDefault() / 2m : 25m,
            ReceiptDate = DateTime.UtcNow.AddDays(-7)
        });
        db.StockLayers.Add(new StockLayer
        {
            ItemId = secondItem.ItemId,
            WarehouseId = warehouse.WarehouseId,
            QtyReceived = 5m,
            QtyRemaining = 5m,
            UnitCost = secondItem.SalePrice.GetValueOrDefault() > 0m ? secondItem.SalePrice.GetValueOrDefault() / 2m : 15m,
            ReceiptDate = DateTime.UtcNow.AddDays(-6)
        });
        return true;
    }

    private static async Task<bool> SeedWarehousesAsync(ErpDbContext db, CancellationToken ct)
    {
        var existingCodes = await db.Warehouses.Select(w => w.Code).ToListAsync(ct);
        var have = existingCodes.ToHashSet(StringComparer.OrdinalIgnoreCase);

        var seeds = new[]
        {
            new Warehouse { Code = "MAIN", Name = "Main Warehouse" },
            new Warehouse { Code = "SHOP", Name = "Sales Counter" }
        };

        var toAdd = seeds.Where(w => !have.Contains(w.Code)).ToList();
        if (toAdd.Count == 0) return false;

        db.Warehouses.AddRange(toAdd);
        return true;
    }

    private static async Task<bool> SeedUomsAsync(ErpDbContext db, CancellationToken ct)
    {
        var existingNames = await db.Uoms.Select(u => u.Name).ToListAsync(ct);
        var have = existingNames.ToHashSet(StringComparer.OrdinalIgnoreCase);

        var seeds = new[]
        {
            new Uom { Name = "PCS" },
            new Uom { Name = "BOX" }
        };

        var toAdd = seeds.Where(u => !have.Contains(u.Name)).ToList();
        if (toAdd.Count == 0) return false;

        db.Uoms.AddRange(toAdd);
        return true;
    }

    private static async Task<bool> SeedCategoriesAsync(ErpDbContext db, CancellationToken ct)
    {
        var existingNames = await db.Categories.Select(c => c.Name).ToListAsync(ct);
        var have = existingNames.ToHashSet(StringComparer.OrdinalIgnoreCase);

        var seeds = new[]
        {
            new Category { Name = "General Goods", Status = EntityStatus.Active, CreatedAt = DateTime.UtcNow },
            new Category { Name = "Accessories", Status = EntityStatus.Active, CreatedAt = DateTime.UtcNow }
        };

        var toAdd = seeds.Where(c => !have.Contains(c.Name)).ToList();
        if (toAdd.Count == 0) return false;

        db.Categories.AddRange(toAdd);
        return true;
    }

    private static async Task<bool> SeedItemsAsync(ErpDbContext db, CancellationToken ct)
    {
        var existingSkus = await db.Items.Select(i => i.Sku).ToListAsync(ct);
        var have = existingSkus.ToHashSet(StringComparer.OrdinalIgnoreCase);

        var category = await db.Categories.AsNoTracking()
            .OrderBy(c => c.CategoryId)
            .FirstOrDefaultAsync(ct);
        var uom = await db.Uoms.AsNoTracking()
            .OrderBy(u => u.UomId)
            .FirstOrDefaultAsync(ct);

        if (category is null || uom is null)
            return false;

        var now = DateTime.UtcNow;
        var seeds = new[]
        {
            new Item
            {
                Sku = "SKU-DEMO-001",
                Name = "Demo Item 1",
                Description = "Seeded sample item for sales documents",
                CategoryId = category.CategoryId,
                BaseUomId = uom.UomId,
                StockNature = StockNature.Stocked,
                TrackingMode = TrackingMode.None,
                SalePrice = 100m,
                Status = EntityStatus.Active,
                CreatedAt = now
            },
            new Item
            {
                Sku = "SKU-DEMO-002",
                Name = "Demo Item 2 (500 ml)",
                Description = "Secondary seeded sample item; carries a content size so the "
                    + "production content-unit path has a fixture",
                CategoryId = category.CategoryId,
                BaseUomId = uom.UomId,
                StockNature = StockNature.Stocked,
                TrackingMode = TrackingMode.None,
                SalePrice = 50m,
                ContentQty = 500m,
                ContentUnit = MeasureUnit.Ml,
                ContentBaseQty = 500m,
                ContentBaseUnit = MeasureUnit.Ml,
                Status = EntityStatus.Active,
                CreatedAt = now
            }
        };

        var toAdd = seeds.Where(i => !have.Contains(i.Sku)).ToList();
        if (toAdd.Count == 0) return false;

        db.Items.AddRange(toAdd);
        return true;
    }

    /// <summary>
    /// Seeds the minimum sales bootstrap data needed for UI/backend development:
    /// a couple of customer rows, current-year document counters, and a few draft
    /// invoice/slip samples when the required master data already exists.
    /// This intentionally never clears or rewrites any existing rows.
    /// </summary>
    private static async Task<bool> SeedSalesAsync(ErpDbContext db, CancellationToken ct)
    {
        var dirty = false;

        dirty |= await SeedSalesCustomersAsync(db, ct);
        dirty |= await SeedSalesSequencesAsync(db, ct);
        dirty |= await SeedSampleSalesDocsAsync(db, ct);

        try
        {
            dirty |= await SeedBundleSalesAsync(db, ct);
        }
        catch
        {
            // Bundle demo data is best-effort only; never block startup because of seed drift.
        }

        return dirty;
    }

    private static async Task<bool> SeedSalesCustomersAsync(ErpDbContext db, CancellationToken ct)
    {
        var existingCodes = await db.Customers.Select(c => c.CustomerCode).ToListAsync(ct);
        var have = existingCodes.ToHashSet(StringComparer.OrdinalIgnoreCase);

        var seeds = new[]
        {
            new Customer
            {
                CustomerCode = "CUST-WALKIN",
                CustomerType = CustomerType.B2C,
                Name = "Walk-in Customer",
                DisplayName = "Walk-in Customer",
                CreditLimit = 0m,
                CreditDays = 0,
                Status = EntityStatus.Active,
                CreatedAt = DateTime.UtcNow
            },
            new Customer
            {
                CustomerCode = "CUST-DEMO",
                CustomerType = CustomerType.B2B,
                Name = "Demo Retail Ltd",
                DisplayName = "Demo Retail Ltd",
                Phone = "+94 11 000 0000",
                Email = "sales@example.com",
                AddressLine1 = "1 Demo Street",
                City = "Colombo",
                Country = "Sri Lanka",
                TaxRegistrationNo = "VAT-DEMO-001",
                CreditLimit = 250000m,
                CreditDays = 30,
                Status = EntityStatus.Active,
                CreatedAt = DateTime.UtcNow
            }
        };

        var toAdd = seeds.Where(c => !have.Contains(c.CustomerCode)).ToList();
        if (toAdd.Count == 0) return false;

        db.Customers.AddRange(toAdd);
        return true;
    }

    private static async Task<bool> SeedSalesSequencesAsync(ErpDbContext db, CancellationToken ct)
    {
        var year = DateTime.UtcNow.Year;
        var existing = await db.NumberSequences
            .Where(s => s.Year == year && (s.DocType == DocumentTypes.SalesInvoice || s.DocType == DocumentTypes.SalesSlip || s.DocType == DocumentTypes.BundleSale))
            .Select(s => s.DocType)
            .ToListAsync(ct);
        var have = existing.ToHashSet(StringComparer.OrdinalIgnoreCase);

        var seeds = new[]
        {
            new NumberSequence { DocType = DocumentTypes.SalesInvoice, Year = year, LastNumber = 0 },
            new NumberSequence { DocType = DocumentTypes.SalesSlip, Year = year, LastNumber = 0 },
            new NumberSequence { DocType = DocumentTypes.BundleSale, Year = year, LastNumber = 0 }
        };

        var toAdd = seeds.Where(s => !have.Contains(s.DocType)).ToList();
        if (toAdd.Count == 0) return false;

        db.NumberSequences.AddRange(toAdd);
        return true;
    }

    private static async Task<bool> SeedBundleSalesAsync(ErpDbContext db, CancellationToken ct)
    {
        if (await db.BundleSaleTemplates.AnyAsync(ct) || await db.BundleSales.AnyAsync(ct))
            return false;

        var customer = await db.Customers.AsNoTracking()
            .OrderBy(c => c.CustomerId)
            .FirstOrDefaultAsync(ct);
        var warehouse = await db.Warehouses.AsNoTracking()
            .OrderBy(w => w.WarehouseId)
            .FirstOrDefaultAsync(ct);
        var secondaryWarehouse = await db.Warehouses.AsNoTracking()
            .OrderByDescending(w => w.WarehouseId)
            .FirstOrDefaultAsync(ct);
        var items = await db.Items.AsNoTracking()
            .OrderBy(i => i.ItemId)
            .Take(2)
            .ToListAsync(ct);
        var uom = await db.Uoms.AsNoTracking()
            .OrderBy(u => u.UomId)
            .FirstOrDefaultAsync(ct);
        var user = await db.Users.AsNoTracking()
            .OrderBy(u => u.UserId)
            .FirstOrDefaultAsync(ct);

        if (customer is null || warehouse is null || secondaryWarehouse is null || items.Count < 2 || uom is null || user is null)
            return false;

        var now = DateTime.UtcNow;
        var template = new BundleSaleTemplate
        {
            TemplateCode = "BND-DEMO-001",
            TemplateName = "Demo Bundle Pack",
            Description = "Seeded fixed bundle template for integration testing",
            Status = EntityStatus.Active,
            CreatedAt = now,
            Lines =
            [
                new BundleSaleTemplateLine
                {
                    ItemId = items[0].ItemId,
                    WarehouseId = warehouse.WarehouseId,
                    Qty = 1m,
                    UnitPrice = items[0].SalePrice.GetValueOrDefault(),
                    IncludeInBundle = true,
                    SortOrder = 1
                },
                new BundleSaleTemplateLine
                {
                    ItemId = items[1].ItemId,
                    WarehouseId = warehouse.WarehouseId,
                    Qty = 1m,
                    UnitPrice = items[1].SalePrice.GetValueOrDefault(),
                    IncludeInBundle = true,
                    SortOrder = 2
                }
            ]
        };

        db.BundleSaleTemplates.Add(template);
        await db.SaveChangesAsync(ct);

        var bundleSales = new[]
        {
            new BundleSale
            {
                BundleNo = $"BND-{now:yyyy}-00001",
                BundleDate = now.Date.AddDays(-2),
                CustomerId = customer.CustomerId,
                CustomerSnapshotName = customer.DisplayName ?? customer.Name,
                WarehouseId = warehouse.WarehouseId,
                CashierUserId = user.UserId,
                BundleSaleTemplateId = template.BundleSaleTemplateId,
                BundleName = "Demo Bundle Draft",
                BundleCode = "BND-DEMO-001",
                Status = BundleSaleStatus.Draft,
                ComponentSubtotal = items[0].SalePrice.GetValueOrDefault() + items[1].SalePrice.GetValueOrDefault(),
                BundlePrice = 0m,
                MarginAmount = -(items[0].SalePrice.GetValueOrDefault() + items[1].SalePrice.GetValueOrDefault()),
                DiscountTotal = items[0].SalePrice.GetValueOrDefault() + items[1].SalePrice.GetValueOrDefault(),
                TaxTotal = 0m,
                GrandTotal = 0m,
                CreatedAt = now.AddDays(-2),
                Lines =
                [
                    new BundleSaleLine
                    {
                        ItemId = items[0].ItemId,
                        Description = items[0].Name,
                        Qty = 1m,
                        WarehouseId = warehouse.WarehouseId,
                        UnitPrice = items[0].SalePrice.GetValueOrDefault(),
                        LineTotal = items[0].SalePrice.GetValueOrDefault(),
                        IncludeInBundle = true,
                        IsComponent = true
                    },
                    new BundleSaleLine
                    {
                        ItemId = items[1].ItemId,
                        Description = items[1].Name,
                        Qty = 1m,
                        WarehouseId = warehouse.WarehouseId,
                        UnitPrice = items[1].SalePrice.GetValueOrDefault(),
                        LineTotal = items[1].SalePrice.GetValueOrDefault(),
                        IncludeInBundle = true,
                        IsComponent = true
                    }
                ]
            },
            new BundleSale
            {
                BundleNo = $"BND-{now:yyyy}-00002",
                BundleDate = now.Date.AddDays(-1),
                CustomerId = customer.CustomerId,
                CustomerSnapshotName = customer.DisplayName ?? customer.Name,
                WarehouseId = warehouse.WarehouseId,
                CashierUserId = user.UserId,
                BundleSaleTemplateId = template.BundleSaleTemplateId,
                BundleName = "Demo Bundle Posted",
                BundleCode = "BND-DEMO-001",
                Status = BundleSaleStatus.Posted,
                ComponentSubtotal = items[0].SalePrice.GetValueOrDefault() + items[1].SalePrice.GetValueOrDefault(),
                BundlePrice = (items[0].SalePrice.GetValueOrDefault() + items[1].SalePrice.GetValueOrDefault()) - 10m,
                MarginAmount = -10m,
                DiscountTotal = 10m,
                TaxTotal = 0m,
                GrandTotal = (items[0].SalePrice.GetValueOrDefault() + items[1].SalePrice.GetValueOrDefault()) - 10m,
                CreatedAt = now.AddDays(-1),
                UpdatedAt = now.AddHours(-2),
                Lines =
                [
                    new BundleSaleLine
                    {
                        ItemId = items[0].ItemId,
                        Description = items[0].Name,
                        Qty = 1m,
                        WarehouseId = warehouse.WarehouseId,
                        UnitPrice = items[0].SalePrice.GetValueOrDefault(),
                        LineTotal = items[0].SalePrice.GetValueOrDefault(),
                        IncludeInBundle = true,
                        IsComponent = true
                    },
                    new BundleSaleLine
                    {
                        ItemId = items[1].ItemId,
                        Description = items[1].Name,
                        Qty = 1m,
                        WarehouseId = warehouse.WarehouseId,
                        UnitPrice = items[1].SalePrice.GetValueOrDefault(),
                        LineTotal = items[1].SalePrice.GetValueOrDefault(),
                        IncludeInBundle = true,
                        IsComponent = true
                    }
                ]
            },
            new BundleSale
            {
                BundleNo = $"BND-{now:yyyy}-00003",
                BundleDate = now.Date,
                CustomerId = customer.CustomerId,
                CustomerSnapshotName = customer.DisplayName ?? customer.Name,
                WarehouseId = secondaryWarehouse.WarehouseId,
                CashierUserId = user.UserId,
                BundleSaleTemplateId = template.BundleSaleTemplateId,
                BundleName = "Demo Bundle Cancelled",
                BundleCode = "BND-DEMO-001",
                Status = BundleSaleStatus.Cancelled,
                ComponentSubtotal = items[0].SalePrice.GetValueOrDefault(),
                BundlePrice = items[0].SalePrice.GetValueOrDefault(),
                MarginAmount = 0m,
                DiscountTotal = 0m,
                TaxTotal = 0m,
                GrandTotal = items[0].SalePrice.GetValueOrDefault(),
                CreatedAt = now,
                UpdatedAt = now,
                Lines =
                [
                    new BundleSaleLine
                    {
                        ItemId = items[0].ItemId,
                        Description = items[0].Name,
                        Qty = 1m,
                        WarehouseId = secondaryWarehouse.WarehouseId,
                        UnitPrice = items[0].SalePrice.GetValueOrDefault(),
                        LineTotal = items[0].SalePrice.GetValueOrDefault(),
                        IncludeInBundle = true,
                        IsComponent = true
                    }
                ]
            }
        };

        db.BundleSales.AddRange(bundleSales);
        return true;
    }

    private static async Task<bool> SeedSampleSalesDocsAsync(ErpDbContext db, CancellationToken ct)
    {
        if (await db.SalesInvoices.AnyAsync(ct) || await db.SalesSlips.AnyAsync(ct))
            return false;

        var customer = await db.Customers.AsNoTracking()
            .OrderBy(c => c.CustomerId)
            .FirstOrDefaultAsync(ct);
        var warehouse = await db.Warehouses.AsNoTracking()
            .OrderBy(w => w.WarehouseId)
            .FirstOrDefaultAsync(ct);
        var secondaryWarehouse = await db.Warehouses.AsNoTracking()
            .OrderByDescending(w => w.WarehouseId)
            .FirstOrDefaultAsync(ct);
        var items = await db.Items.AsNoTracking()
            .OrderBy(i => i.ItemId)
            .Take(2)
            .ToListAsync(ct);
        var uom = await db.Uoms.AsNoTracking()
            .OrderBy(u => u.UomId)
            .FirstOrDefaultAsync(ct);
        var user = await db.Users.AsNoTracking()
            .OrderBy(u => u.UserId)
            .FirstOrDefaultAsync(ct);

        if (customer is null || warehouse is null || secondaryWarehouse is null || items.Count < 2 || uom is null || user is null)
            return false;

        var postableItem = items[0];
        var shortageItem = items[1];
        var today = DateTime.UtcNow.Date;
        var createdAt = DateTime.UtcNow.AddDays(-1);

        db.SalesInvoices.AddRange(
            new SalesInvoice
            {
                InvoiceNo = $"SI-{today:yyyy}-00001",
                InvoiceDate = today.AddDays(-2),
                CustomerId = customer.CustomerId,
                CustomerSnapshotName = customer.Name,
                CustomerSnapshotTaxNo = customer.TaxRegistrationNo,
                WarehouseId = warehouse.WarehouseId,
                InvoiceType = SalesInvoiceType.B2C,
                Status = SalesInvoiceStatus.Draft,
                Subtotal = 200m,
                DiscountTotal = 0m,
                TaxTotal = 0m,
                GrandTotal = 200m,
                RoundOff = 0m,
                NetPayable = 200m,
                PaidAmount = 0m,
                BalanceAmount = 200m,
                CreatedBy = user.UserId,
                CreatedAt = createdAt,
                Lines =
                [
                    new SalesInvoiceLine
                    {
                        ItemId = postableItem.ItemId,
                        Description = postableItem.Name,
                        Qty = 2m,
                        FreeQty = 0m,
                        WarehouseId = warehouse.WarehouseId,
                        UnitPrice = 100m,
                        BaseCost = 0m,
                        PriceSource = "seed",
                        DiscountMode = SalesDiscountMode.Percentage,
                        DiscountPct = 0m,
                        DiscountAmount = 0m,
                        NetUnitPrice = 100m,
                        LineTotal = 200m,
                        TaxPct = 0m,
                        TaxAmount = 0m,
                        IsFreeIssue = false
                    }
                ]
            },
            new SalesInvoice
            {
                InvoiceNo = $"SI-{today:yyyy}-00002",
                InvoiceDate = today.AddDays(-1),
                CustomerId = customer.CustomerId,
                CustomerSnapshotName = customer.Name,
                CustomerSnapshotTaxNo = customer.TaxRegistrationNo,
                WarehouseId = secondaryWarehouse.WarehouseId,
                InvoiceType = SalesInvoiceType.B2B,
                Status = SalesInvoiceStatus.Draft,
                Subtotal = 300m,
                DiscountTotal = 0m,
                TaxTotal = 0m,
                GrandTotal = 300m,
                RoundOff = 0m,
                NetPayable = 300m,
                PaidAmount = 0m,
                BalanceAmount = 300m,
                CreatedBy = user.UserId,
                CreatedAt = createdAt,
                Lines =
                [
                    new SalesInvoiceLine
                    {
                        ItemId = shortageItem.ItemId,
                        Description = shortageItem.Name,
                        Qty = 6m,
                        FreeQty = 0m,
                        WarehouseId = secondaryWarehouse.WarehouseId,
                        UnitPrice = 50m,
                        BaseCost = 0m,
                        PriceSource = "seed",
                        DiscountMode = SalesDiscountMode.Percentage,
                        DiscountPct = 0m,
                        DiscountAmount = 0m,
                        NetUnitPrice = 50m,
                        LineTotal = 300m,
                        TaxPct = 0m,
                        TaxAmount = 0m,
                        IsFreeIssue = false
                    }
                ]
            },
            new SalesInvoice
            {
                InvoiceNo = $"SI-{today:yyyy}-00003",
                InvoiceDate = today,
                CustomerId = customer.CustomerId,
                CustomerSnapshotName = customer.Name,
                CustomerSnapshotTaxNo = customer.TaxRegistrationNo,
                WarehouseId = warehouse.WarehouseId,
                InvoiceType = SalesInvoiceType.B2C,
                Status = SalesInvoiceStatus.Posted,
                Subtotal = 100m,
                DiscountTotal = 0m,
                TaxTotal = 0m,
                GrandTotal = 100m,
                RoundOff = 0m,
                NetPayable = 100m,
                PaidAmount = 100m,
                BalanceAmount = 0m,
                CreatedBy = user.UserId,
                CreatedAt = createdAt,
                UpdatedAt = DateTime.UtcNow,
                Lines =
                [
                    new SalesInvoiceLine
                    {
                        ItemId = postableItem.ItemId,
                        Description = postableItem.Name,
                        Qty = 1m,
                        FreeQty = 0m,
                        WarehouseId = warehouse.WarehouseId,
                        UnitPrice = 100m,
                        BaseCost = 0m,
                        PriceSource = "seed",
                        DiscountMode = SalesDiscountMode.Percentage,
                        DiscountPct = 0m,
                        DiscountAmount = 0m,
                        NetUnitPrice = 100m,
                        LineTotal = 100m,
                        TaxPct = 0m,
                        TaxAmount = 0m,
                        IsFreeIssue = false
                    }
                ]
            }
        );

        db.SalesSlips.AddRange(
            new SalesSlip
            {
                SlipNo = $"SSL-{today:yyyy}-00001",
                SlipDate = today.AddDays(-2),
                CustomerId = customer.CustomerId,
                CustomerSnapshotName = customer.Name,
                WarehouseId = warehouse.WarehouseId,
                CashierUserId = user.UserId,
                Status = SalesSlipStatus.Draft,
                Subtotal = 50m,
                DiscountTotal = 0m,
                TaxTotal = 0m,
                GrandTotal = 50m,
                PaidAmount = 0m,
                BalanceAmount = 50m,
                CreatedAt = createdAt,
                Lines =
                [
                    new SalesSlipLine
                    {
                        ItemId = postableItem.ItemId,
                        Description = postableItem.Name,
                        Qty = 1m,
                        FreeQty = 0m,
                        WarehouseId = warehouse.WarehouseId,
                        UnitPrice = 50m,
                        BaseCost = 0m,
                        PriceSource = "seed",
                        DiscountMode = SalesDiscountMode.Percentage,
                        DiscountPct = 0m,
                        DiscountAmount = 0m,
                        NetUnitPrice = 50m,
                        LineTotal = 50m,
                        TaxPct = 0m,
                        TaxAmount = 0m,
                        IsFreeIssue = false
                    }
                ]
            },
            new SalesSlip
            {
                SlipNo = $"SSL-{today:yyyy}-00002",
                SlipDate = today.AddDays(-1),
                CustomerId = customer.CustomerId,
                CustomerSnapshotName = customer.Name,
                WarehouseId = secondaryWarehouse.WarehouseId,
                CashierUserId = user.UserId,
                Status = SalesSlipStatus.Draft,
                Subtotal = 150m,
                DiscountTotal = 15m,
                TaxTotal = 0m,
                GrandTotal = 135m,
                PaidAmount = 0m,
                BalanceAmount = 135m,
                CreatedAt = createdAt,
                Lines =
                [
                    new SalesSlipLine
                    {
                        ItemId = shortageItem.ItemId,
                        Description = shortageItem.Name,
                        Qty = 3m,
                        FreeQty = 0m,
                        WarehouseId = secondaryWarehouse.WarehouseId,
                        UnitPrice = 50m,
                        BaseCost = 0m,
                        PriceSource = "seed",
                        DiscountMode = SalesDiscountMode.Percentage,
                        DiscountPct = 10m,
                        DiscountAmount = 15m,
                        NetUnitPrice = 45m,
                        LineTotal = 135m,
                        TaxPct = 0m,
                        TaxAmount = 0m,
                        IsFreeIssue = false
                    }
                ]
            }
        );

        return true;
    }
}
