using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using SolutionErp.Domain.PurchaseEvaluations;

namespace SolutionErp.Infrastructure.Persistence.Configurations;

public class PurchaseEvaluationConfiguration : IEntityTypeConfiguration<PurchaseEvaluation>
{
    public void Configure(EntityTypeBuilder<PurchaseEvaluation> b)
    {
        b.ToTable("PurchaseEvaluations");
        b.HasKey(x => x.Id);

        b.Property(x => x.MaPhieu).HasMaxLength(100);
        b.Property(x => x.Type).HasConversion<int>();
        b.Property(x => x.Phase).HasConversion<int>();
        b.Property(x => x.RejectedFromPhase).HasConversion<int?>();
        b.Property(x => x.TenGoiThau).HasMaxLength(500).IsRequired();
        b.Property(x => x.DiaDiem).HasMaxLength(500);
        b.Property(x => x.MoTa).HasMaxLength(2000);
        // [HoSoLink] hyperlink thư mục hồ sơ NAS — nvarchar(1000) nullable, KHÔNG index.
        b.Property(x => x.HoSoLink).HasMaxLength(1000);
        b.Property(x => x.PaymentTerms).HasColumnType("nvarchar(max)");
        // [S61 Mig 50] 2 cột ngân sách mới thay BudgetManual* — precision giữ (18,2).
        b.Property(x => x.BudgetPeriodAmount).HasPrecision(18, 2);
        b.Property(x => x.ExpectedRemainingAmount).HasPrecision(18, 2);
        // [Mig 59 2026-06-24] "NS kỳ này" cột CCM (Section B 3 cột) — decimal(18,2)
        // nullable, mirror BudgetPeriodAmount. Nhập role-gate Admin|CostControl.
        b.Property(x => x.CcmBudgetPeriodAmount).HasColumnType("decimal(18,2)");
        // [Mig 54 2026-06-18] Giá đề xuất PRO/CCM + giá chốt khi duyệt — precision (18,2)
        // mirror các cột tiền khác. ApprovedPriceSource nvarchar(20): Ncc/ProMin/ProMax/Ccm.
        b.Property(x => x.ProSuggestedMinPrice).HasPrecision(18, 2);
        b.Property(x => x.ProSuggestedMaxPrice).HasPrecision(18, 2);
        b.Property(x => x.CcmSuggestedPrice).HasPrecision(18, 2);
        b.Property(x => x.ApprovedPriceAmount).HasPrecision(18, 2);
        // [S117 Mig 66] Max của khoảng duyệt (source ProMinMax) — mirror precision (18,2).
        b.Property(x => x.ApprovedPriceMaxAmount).HasPrecision(18, 2);
        b.Property(x => x.ApprovedPriceSource).HasMaxLength(20);
        // [Mig 57 2026-06-19] Ghi chú giải thích giá đề xuất PRO/CCM — nvarchar(1000)
        // nullable, KHÔNG index (free-text). Mirror HoSoLink + PeWorkItemBudget.CcmNote.
        b.Property(x => x.ProSuggestedPriceNote).HasMaxLength(1000);
        b.Property(x => x.CcmSuggestedPriceNote).HasMaxLength(1000);
        // [S97 2026-07-01] Runtime finalize-fact — bit NOT NULL default false (mirror IsUrgent* bool).
        b.Property(x => x.EndedByLevelFinalize).HasDefaultValue(false);
        // [S133 Mig 67] Snapshot ngân sách phiếu DaDuyet — 6 decimal (18,2) + 2 note (1000)
        // mirror precision cột ApprovedPrice*/PeWorkItemBudget. Tất cả nullable (backfill Mig 67).
        b.Property(x => x.ApprovedBudgetProInitialAmount).HasPrecision(18, 2);
        b.Property(x => x.ApprovedBudgetProAdjustmentAmount).HasPrecision(18, 2);
        b.Property(x => x.ApprovedBudgetCcmInitialAmount).HasPrecision(18, 2);
        b.Property(x => x.ApprovedBudgetCcmAdjustmentAmount).HasPrecision(18, 2);
        b.Property(x => x.ApprovedBudgetPrevSubmittedTotal).HasPrecision(18, 2);
        b.Property(x => x.ApprovedBudgetPrevSelectedTotal).HasPrecision(18, 2);
        b.Property(x => x.ApprovedBudgetProNote).HasMaxLength(1000);
        b.Property(x => x.ApprovedBudgetCcmNote).HasMaxLength(1000);

        b.HasIndex(x => x.MaPhieu).IsUnique().HasFilter("[MaPhieu] IS NOT NULL");
        b.HasIndex(x => new { x.Phase, x.IsDeleted });
        b.HasIndex(x => x.ProjectId);
        // [Mig 49 S57bis] WorkItemId scalar loose-Guid — index lọc query, KHÔNG
        // HasOne/FK vật lý (convention PE: chỉ ApprovalWorkflowId có FK).
        b.HasIndex(x => x.WorkItemId);
        b.HasIndex(x => x.SlaDeadline);
        b.HasIndex(x => x.WorkflowDefinitionId);
        b.HasIndex(x => x.ApprovalWorkflowId);
        b.HasIndex(x => x.ContractId);

        // FK ApprovalWorkflowId Restrict (Mig 23 Session 17) — schema mới
        // ApprovalWorkflowsV2 pin lúc create. Restrict để KHÔNG xóa workflow
        // nếu còn phiếu pin.
        b.HasOne<SolutionErp.Domain.ApprovalWorkflowsV2.ApprovalWorkflow>()
            .WithMany()
            .HasForeignKey(x => x.ApprovalWorkflowId)
            .OnDelete(DeleteBehavior.Restrict);

        b.HasMany(x => x.Suppliers).WithOne(s => s.PurchaseEvaluation).HasForeignKey(s => s.PurchaseEvaluationId).OnDelete(DeleteBehavior.Cascade);
        b.HasMany(x => x.Details).WithOne(d => d.PurchaseEvaluation).HasForeignKey(d => d.PurchaseEvaluationId).OnDelete(DeleteBehavior.Cascade);
        b.HasMany(x => x.Approvals).WithOne(a => a.PurchaseEvaluation).HasForeignKey(a => a.PurchaseEvaluationId).OnDelete(DeleteBehavior.Cascade);
        b.HasMany(x => x.Changelogs).WithOne(c => c.PurchaseEvaluation).HasForeignKey(c => c.PurchaseEvaluationId).OnDelete(DeleteBehavior.Cascade);
        b.HasMany(x => x.Attachments).WithOne(a => a.PurchaseEvaluation).HasForeignKey(a => a.PurchaseEvaluationId).OnDelete(DeleteBehavior.Cascade);
        b.HasMany(x => x.DepartmentOpinions).WithOne(o => o.PurchaseEvaluation).HasForeignKey(o => o.PurchaseEvaluationId).OnDelete(DeleteBehavior.Cascade);
        // Quotes không FK trực tiếp tới PurchaseEvaluation (đi qua Detail) —
        // nhưng collection navigation có nên cần config riêng bên dưới.

        b.HasQueryFilter(x => !x.IsDeleted);
    }
}

public class PurchaseEvaluationSupplierConfiguration : IEntityTypeConfiguration<PurchaseEvaluationSupplier>
{
    public void Configure(EntityTypeBuilder<PurchaseEvaluationSupplier> b)
    {
        b.ToTable("PurchaseEvaluationSuppliers");
        b.HasKey(x => x.Id);

        b.Property(x => x.DisplayName).HasMaxLength(200);
        b.Property(x => x.ContactName).HasMaxLength(200);
        b.Property(x => x.ContactEmail).HasMaxLength(200);
        b.Property(x => x.ContactPhone).HasMaxLength(50);
        b.Property(x => x.PaymentTermText).HasMaxLength(200);
        b.Property(x => x.Note).HasMaxLength(500);

        // [Mig 58] Multi-winner flag — default false (mirror per-slot bool pattern).
        b.Property(x => x.IsWinner).HasDefaultValue(false);

        b.HasIndex(x => new { x.PurchaseEvaluationId, x.SupplierId }).IsUnique();
        b.HasIndex(x => x.SupplierId);
    }
}

public class PurchaseEvaluationDetailConfiguration : IEntityTypeConfiguration<PurchaseEvaluationDetail>
{
    public void Configure(EntityTypeBuilder<PurchaseEvaluationDetail> b)
    {
        b.ToTable("PurchaseEvaluationDetails");
        b.HasKey(x => x.Id);

        b.Property(x => x.GroupCode).HasMaxLength(50).IsRequired();
        b.Property(x => x.GroupName).HasMaxLength(200).IsRequired();
        b.Property(x => x.ItemCode).HasMaxLength(100);
        b.Property(x => x.NoiDung).HasMaxLength(500).IsRequired();
        b.Property(x => x.DonViTinh).HasMaxLength(50);
        b.Property(x => x.GhiChu).HasMaxLength(1000);
        b.Property(x => x.KhoiLuongNganSach).HasPrecision(18, 4);
        b.Property(x => x.KhoiLuongThiCong).HasPrecision(18, 4);
        b.Property(x => x.DonGiaNganSach).HasPrecision(18, 2);
        b.Property(x => x.ThanhTienNganSach).HasPrecision(18, 2);

        b.HasIndex(x => new { x.PurchaseEvaluationId, x.Order });

        b.HasMany(x => x.Quotes).WithOne(q => q.Detail).HasForeignKey(q => q.PurchaseEvaluationDetailId).OnDelete(DeleteBehavior.Cascade);
    }
}

public class PurchaseEvaluationQuoteConfiguration : IEntityTypeConfiguration<PurchaseEvaluationQuote>
{
    public void Configure(EntityTypeBuilder<PurchaseEvaluationQuote> b)
    {
        b.ToTable("PurchaseEvaluationQuotes");
        b.HasKey(x => x.Id);

        b.Property(x => x.BgVat).HasPrecision(18, 2);
        b.Property(x => x.ChuaVat).HasPrecision(18, 2);
        b.Property(x => x.ThanhTien).HasPrecision(18, 2);
        b.Property(x => x.Note).HasMaxLength(500);

        b.HasIndex(x => new { x.PurchaseEvaluationDetailId, x.PurchaseEvaluationSupplierId }).IsUnique();

        // Quote → Supplier (restrict — không xóa Supplier-row khỏi phiếu nếu còn quote)
        b.HasOne(x => x.Supplier)
            .WithMany()
            .HasForeignKey(x => x.PurchaseEvaluationSupplierId)
            .OnDelete(DeleteBehavior.Restrict);
    }
}

public class PurchaseEvaluationApprovalConfiguration : IEntityTypeConfiguration<PurchaseEvaluationApproval>
{
    public void Configure(EntityTypeBuilder<PurchaseEvaluationApproval> b)
    {
        b.ToTable("PurchaseEvaluationApprovals");
        b.HasKey(x => x.Id);

        b.Property(x => x.FromPhase).HasConversion<int>();
        b.Property(x => x.ToPhase).HasConversion<int>();
        b.Property(x => x.Decision).HasConversion<int>();
        b.Property(x => x.Comment).HasMaxLength(1000);

        b.HasIndex(x => new { x.PurchaseEvaluationId, x.ApprovedAt });
    }
}

public class PurchaseEvaluationChangelogConfiguration : IEntityTypeConfiguration<PurchaseEvaluationChangelog>
{
    public void Configure(EntityTypeBuilder<PurchaseEvaluationChangelog> b)
    {
        b.ToTable("PurchaseEvaluationChangelogs");
        b.HasKey(x => x.Id);

        b.Property(x => x.EntityType).HasConversion<int>();
        b.Property(x => x.Action).HasConversion<int>();
        b.Property(x => x.PhaseAtChange).HasConversion<int>();
        b.Property(x => x.UserName).HasMaxLength(200);
        b.Property(x => x.Summary).HasMaxLength(500);
        b.Property(x => x.ContextNote).HasMaxLength(2000);
        b.Property(x => x.FieldChangesJson).HasColumnType("nvarchar(max)");

        b.HasIndex(x => new { x.PurchaseEvaluationId, x.CreatedAt });
        b.HasIndex(x => new { x.PurchaseEvaluationId, x.EntityType });
    }
}

public class PurchaseEvaluationAttachmentConfiguration : IEntityTypeConfiguration<PurchaseEvaluationAttachment>
{
    public void Configure(EntityTypeBuilder<PurchaseEvaluationAttachment> b)
    {
        b.ToTable("PurchaseEvaluationAttachments");
        b.HasKey(x => x.Id);

        b.Property(x => x.FileName).HasMaxLength(255).IsRequired();
        b.Property(x => x.StoragePath).HasMaxLength(500).IsRequired();
        b.Property(x => x.ContentType).HasMaxLength(100).IsRequired();
        b.Property(x => x.Purpose).HasConversion<int>();
        b.Property(x => x.Note).HasMaxLength(500);

        b.HasIndex(x => x.PurchaseEvaluationId);
        b.HasIndex(x => x.PurchaseEvaluationSupplierId);
    }
}

public class PurchaseEvaluationWorkflowDefinitionConfiguration : IEntityTypeConfiguration<PurchaseEvaluationWorkflowDefinition>
{
    public void Configure(EntityTypeBuilder<PurchaseEvaluationWorkflowDefinition> e)
    {
        e.ToTable("PurchaseEvaluationWorkflowDefinitions");
        e.Property(x => x.Code).HasMaxLength(100).IsRequired();
        e.Property(x => x.Name).HasMaxLength(200).IsRequired();
        e.Property(x => x.Description).HasMaxLength(1000);
        e.Property(x => x.EvaluationType).HasConversion<int>();

        e.HasIndex(x => new { x.Code, x.Version }).IsUnique();
        e.HasIndex(x => new { x.EvaluationType, x.IsActive });
    }
}

public class PurchaseEvaluationWorkflowStepConfiguration : IEntityTypeConfiguration<PurchaseEvaluationWorkflowStep>
{
    public void Configure(EntityTypeBuilder<PurchaseEvaluationWorkflowStep> e)
    {
        e.ToTable("PurchaseEvaluationWorkflowSteps");
        e.Property(x => x.Name).HasMaxLength(200).IsRequired();
        e.Property(x => x.Phase).HasConversion<int>();
        e.Property(x => x.PositionLevel).HasConversion<int?>();   // Mig 21

        e.HasOne(x => x.Definition)
            .WithMany(d => d.Steps)
            .HasForeignKey(x => x.PurchaseEvaluationWorkflowDefinitionId)
            .OnDelete(DeleteBehavior.Cascade);

        // Mig 21 — FK Department Restrict.
        e.HasOne<SolutionErp.Domain.Master.Department>()
            .WithMany()
            .HasForeignKey(x => x.DepartmentId)
            .OnDelete(DeleteBehavior.Restrict);

        e.HasIndex(x => new { x.PurchaseEvaluationWorkflowDefinitionId, x.Order });
        e.HasIndex(x => x.DepartmentId);
    }
}

public class PurchaseEvaluationWorkflowStepApproverConfiguration : IEntityTypeConfiguration<PurchaseEvaluationWorkflowStepApprover>
{
    public void Configure(EntityTypeBuilder<PurchaseEvaluationWorkflowStepApprover> e)
    {
        e.ToTable("PurchaseEvaluationWorkflowStepApprovers");
        e.Property(x => x.Kind).HasConversion<int>();
        e.Property(x => x.AssignmentValue).HasMaxLength(100).IsRequired();

        e.HasOne(x => x.Step)
            .WithMany(s => s.Approvers)
            .HasForeignKey(x => x.PurchaseEvaluationWorkflowStepId)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

// Mirror ContractCodeSequenceConfiguration — Prefix là PK, atomic UPDATE qua
// SERIALIZABLE transaction trong PurchaseEvaluationCodeGenerator.
public class PurchaseEvaluationCodeSequenceConfiguration
    : IEntityTypeConfiguration<PurchaseEvaluationCodeSequence>
{
    public void Configure(EntityTypeBuilder<PurchaseEvaluationCodeSequence> b)
    {
        b.ToTable("PurchaseEvaluationCodeSequences");
        b.HasKey(x => x.Prefix);
        b.Property(x => x.Prefix).HasMaxLength(100);
    }
}

public class PurchaseEvaluationDepartmentOpinionConfiguration
    : IEntityTypeConfiguration<PurchaseEvaluationDepartmentOpinion>
{
    public void Configure(EntityTypeBuilder<PurchaseEvaluationDepartmentOpinion> b)
    {
        b.ToTable("PurchaseEvaluationDepartmentOpinions");
        b.HasKey(x => x.Id);

        b.Property(x => x.Kind).HasConversion<int>();
        b.Property(x => x.Opinion).HasMaxLength(2000);
        b.Property(x => x.UserName).HasMaxLength(200);

        // Each PE × Kind unique — max 1 ý kiến per phòng ban per phiếu.
        // UPDATE in-place khi user đổi ý → audit qua Changelog.
        b.HasIndex(x => new { x.PurchaseEvaluationId, x.Kind }).IsUnique();
    }
}
