using foodmarket.Domain.Catalog;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace foodmarket.Infrastructure.Persistence.Configurations;

internal static class CatalogConfigurations
{
    public static void ConfigureCatalog(this ModelBuilder b)
    {
        b.Entity<Country>(ConfigureCountry);
        b.Entity<Currency>(ConfigureCurrency);
        b.Entity<UnitOfMeasure>(ConfigureUnit);
        b.Entity<OrgUnitOfMeasure>(ConfigureOrgUnit);
        b.Entity<Counterparty>(ConfigureCounterparty);
        b.Entity<Store>(ConfigureStore);
        b.Entity<RetailPoint>(ConfigureRetailPoint);
        b.Entity<ProductGroup>(ConfigureProductGroup);
        b.Entity<PriceType>(ConfigurePriceType);
        b.Entity<Product>(ConfigureProduct);
        b.Entity<ProductPrice>(ConfigureProductPrice);
        b.Entity<ProductBarcode>(ConfigureBarcode);
        b.Entity<ProductImage>(ConfigureImage);
    }

    private static void ConfigureCountry(EntityTypeBuilder<Country> b)
    {
        b.ToTable("countries");
        b.Property(x => x.Code).HasMaxLength(2).IsRequired();
        b.Property(x => x.Name).HasMaxLength(100).IsRequired();
        b.Property(x => x.VatRate).HasPrecision(5, 2);
        b.HasOne(x => x.DefaultCurrency).WithMany().HasForeignKey(x => x.DefaultCurrencyId).OnDelete(DeleteBehavior.Restrict);
        b.HasIndex(x => x.Code).IsUnique();
    }

    private static void ConfigureCurrency(EntityTypeBuilder<Currency> b)
    {
        b.ToTable("currencies");
        b.Property(x => x.Code).HasMaxLength(3).IsRequired();
        b.Property(x => x.Name).HasMaxLength(100).IsRequired();
        b.Property(x => x.Symbol).HasMaxLength(5).IsRequired();
        b.HasIndex(x => x.Code).IsUnique();
    }

    private static void ConfigureUnit(EntityTypeBuilder<UnitOfMeasure> b)
    {
        b.ToTable("units_of_measure");
        b.Property(x => x.Code).HasMaxLength(10).IsRequired();
        b.Property(x => x.Name).HasMaxLength(100).IsRequired();
        b.Property(x => x.IsActive).HasDefaultValue(true);
        // Phase5c: после миграции OrganizationId всегда NULL — глобальный справочник.
        // Уникальность по Code только среди активных, чтобы можно было
        // soft-delete старую запись и создать новую с тем же кодом.
        b.HasIndex(x => x.Code).IsUnique().HasFilter("\"IsActive\" = true");
    }

    private static void ConfigureOrgUnit(EntityTypeBuilder<OrgUnitOfMeasure> b)
    {
        b.ToTable("org_units_of_measure");
        b.HasKey(x => new { x.OrganizationId, x.UnitOfMeasureId });
        b.HasOne(x => x.UnitOfMeasure).WithMany().HasForeignKey(x => x.UnitOfMeasureId).OnDelete(DeleteBehavior.Restrict);
        b.HasIndex(x => x.UnitOfMeasureId);
    }

    private static void ConfigureCounterparty(EntityTypeBuilder<Counterparty> b)
    {
        b.ToTable("counterparties");
        b.Property(x => x.Name).HasMaxLength(255).IsRequired();
        b.Property(x => x.LegalName).HasMaxLength(500);
        b.Property(x => x.Bin).HasMaxLength(20);
        b.Property(x => x.Iin).HasMaxLength(20);
        b.Property(x => x.TaxNumber).HasMaxLength(20);
        b.Property(x => x.Phone).HasMaxLength(50);
        b.Property(x => x.Email).HasMaxLength(255);
        b.Property(x => x.BankName).HasMaxLength(255);
        b.Property(x => x.BankAccount).HasMaxLength(50);
        b.Property(x => x.Bik).HasMaxLength(20);
        b.Property(x => x.ContactPerson).HasMaxLength(255);
        b.HasOne(x => x.Country).WithMany().HasForeignKey(x => x.CountryId).OnDelete(DeleteBehavior.Restrict);
        b.HasIndex(x => new { x.OrganizationId, x.Name });
        b.HasIndex(x => new { x.OrganizationId, x.Bin });
    }

    private static void ConfigureStore(EntityTypeBuilder<Store> b)
    {
        b.ToTable("stores");
        b.Property(x => x.Name).HasMaxLength(200).IsRequired();
        b.Property(x => x.Code).HasMaxLength(50);
        b.Property(x => x.Phone).HasMaxLength(50);
        b.Property(x => x.ManagerName).HasMaxLength(200);
        b.HasIndex(x => new { x.OrganizationId, x.Name });
    }

    private static void ConfigureRetailPoint(EntityTypeBuilder<RetailPoint> b)
    {
        b.ToTable("retail_points");
        b.Property(x => x.Name).HasMaxLength(200).IsRequired();
        b.Property(x => x.Code).HasMaxLength(50);
        b.Property(x => x.Phone).HasMaxLength(50);
        b.Property(x => x.FiscalSerial).HasMaxLength(50);
        b.Property(x => x.FiscalRegNumber).HasMaxLength(50);
        b.HasOne(x => x.Store).WithMany().HasForeignKey(x => x.StoreId).OnDelete(DeleteBehavior.Restrict);
        b.HasIndex(x => new { x.OrganizationId, x.Name });
    }

    private static void ConfigureProductGroup(EntityTypeBuilder<ProductGroup> b)
    {
        b.ToTable("product_groups");
        b.Property(x => x.Name).HasMaxLength(200).IsRequired();
        b.Property(x => x.Path).HasMaxLength(1000);
        b.HasOne(x => x.Parent)
            .WithMany(x => x.Children)
            .HasForeignKey(x => x.ParentId)
            .OnDelete(DeleteBehavior.Restrict);
        b.HasIndex(x => new { x.OrganizationId, x.ParentId });
        b.HasIndex(x => new { x.OrganizationId, x.Path });
    }

    private static void ConfigurePriceType(EntityTypeBuilder<PriceType> b)
    {
        b.ToTable("price_types");
        b.Property(x => x.Name).HasMaxLength(100).IsRequired();
        b.HasIndex(x => new { x.OrganizationId, x.Name }).IsUnique();
    }

    private static void ConfigureProduct(EntityTypeBuilder<Product> b)
    {
        b.ToTable("products");
        b.Property(x => x.Name).HasMaxLength(500).IsRequired();
        b.Property(x => x.Article).HasMaxLength(500);
        b.Property(x => x.MinStock).HasPrecision(18, 4);
        b.Property(x => x.MaxStock).HasPrecision(18, 4);
        b.Property(x => x.ReferencePrice).HasPrecision(18, 4);
        b.Property(x => x.Cost).HasPrecision(18, 4);
        b.Property(x => x.ImageUrl).HasMaxLength(1000);

        // VatEnabled defaults to true в БД — при миграции existing rows сохраняют true.
        b.Property(x => x.VatEnabled).HasDefaultValue(true);
        b.HasOne(x => x.UnitOfMeasure).WithMany().HasForeignKey(x => x.UnitOfMeasureId).OnDelete(DeleteBehavior.Restrict);
        b.HasOne(x => x.ProductGroup).WithMany().HasForeignKey(x => x.ProductGroupId).OnDelete(DeleteBehavior.Restrict);
        b.HasOne(x => x.DefaultSupplier).WithMany().HasForeignKey(x => x.DefaultSupplierId).OnDelete(DeleteBehavior.Restrict);
        b.HasOne(x => x.CountryOfOrigin).WithMany().HasForeignKey(x => x.CountryOfOriginId).OnDelete(DeleteBehavior.Restrict);
        b.HasOne(x => x.PurchaseCurrency).WithMany().HasForeignKey(x => x.PurchaseCurrencyId).OnDelete(DeleteBehavior.Restrict);

        b.HasIndex(x => new { x.OrganizationId, x.Name });
        b.HasIndex(x => new { x.OrganizationId, x.Article });
        b.HasIndex(x => new { x.OrganizationId, x.ProductGroupId });
    }

    private static void ConfigureProductPrice(EntityTypeBuilder<ProductPrice> b)
    {
        b.ToTable("product_prices");
        b.Property(x => x.Amount).HasPrecision(18, 4);
        b.HasOne(x => x.Product).WithMany(p => p.Prices).HasForeignKey(x => x.ProductId).OnDelete(DeleteBehavior.Cascade);
        b.HasOne(x => x.PriceType).WithMany().HasForeignKey(x => x.PriceTypeId).OnDelete(DeleteBehavior.Restrict);
        b.HasOne(x => x.Currency).WithMany().HasForeignKey(x => x.CurrencyId).OnDelete(DeleteBehavior.Restrict);
        b.HasIndex(x => new { x.ProductId, x.PriceTypeId }).IsUnique();
    }

    private static void ConfigureBarcode(EntityTypeBuilder<ProductBarcode> b)
    {
        b.ToTable("product_barcodes");
        // Up to 500 to accommodate GS1 DataMatrix / crypto-tail tracking codes (Честный ЗНАК etc.)
        b.Property(x => x.Code).HasMaxLength(500).IsRequired();
        b.HasOne(x => x.Product).WithMany(p => p.Barcodes).HasForeignKey(x => x.ProductId).OnDelete(DeleteBehavior.Cascade);
        b.HasIndex(x => new { x.OrganizationId, x.Code }).IsUnique();
    }

    private static void ConfigureImage(EntityTypeBuilder<ProductImage> b)
    {
        b.ToTable("product_images");
        b.Property(x => x.Url).HasMaxLength(1000).IsRequired();
        b.HasOne(x => x.Product).WithMany(p => p.Images).HasForeignKey(x => x.ProductId).OnDelete(DeleteBehavior.Cascade);
        b.HasIndex(x => x.ProductId);
    }
}
