using FluentValidation;
using MediatR;
using Microsoft.EntityFrameworkCore;
using SolutionErp.Application.Common.Exceptions;
using SolutionErp.Application.Common.Interfaces;
using SolutionErp.Application.Contracts.Dtos;
using SolutionErp.Domain.Contracts;
using SolutionErp.Domain.Contracts.Details;
using static SolutionErp.Application.Contracts.ContractDetailsHelpers;

namespace SolutionErp.Application.Contracts;

// 7 ContractType-specific Details CRUD — pattern lặp nhưng schema khác nhau,
// keep các handler riêng để TS strict mode FE bắt typo + IntelliSense.
//
// Endpoint: GET /api/contracts/{id}/details (bundle bộ + auto theo Type)
//           POST /api/contracts/{id}/details (body có Type discriminator)
//           PUT /api/contracts/{id}/details/{detailId}
//           DELETE /api/contracts/{id}/details/{detailId}
//
// Helper: handler resolve loại HĐ qua Contract.Type rồi dispatch vào DbSet
// tương ứng. Validate detail thuộc đúng contract+type.

// ========== GET bundle (Read) ==========

public record GetContractDetailsQuery(Guid ContractId) : IRequest<ContractDetailsBundleDto>;

public class GetContractDetailsQueryHandler(IApplicationDbContext db) : IRequestHandler<GetContractDetailsQuery, ContractDetailsBundleDto>
{
    public async Task<ContractDetailsBundleDto> Handle(GetContractDetailsQuery request, CancellationToken ct)
    {
        var contract = await db.Contracts.AsNoTracking().FirstOrDefaultAsync(c => c.Id == request.ContractId, ct)
            ?? throw new NotFoundException("Contract", request.ContractId);

        // Chỉ load list tương ứng với Type — 6 còn lại empty (avoid 7 query waste)
        var bundle = new ContractDetailsBundleDto(
            contract.Type,
            ThauPhu: new(), GiaoKhoan: new(), NhaCungCap: new(), DichVu: new(),
            MuaBan: new(), NguyenTacNcc: new(), NguyenTacDv: new());

        switch (contract.Type)
        {
            case ContractType.HopDongThauPhu:
                bundle = bundle with
                {
                    ThauPhu = await db.ThauPhuDetails.AsNoTracking()
                        .Where(d => d.ContractId == request.ContractId)
                        .OrderBy(d => d.Order)
                        .Select(d => new ThauPhuDetailDto(d.Id, d.Order, d.HangMuc, d.DonViTinh, d.KhoiLuong, d.DonGia, d.ThanhTien, d.ThoiGianHoanThanh, d.GhiChu))
                        .ToListAsync(ct),
                };
                break;

            case ContractType.HopDongGiaoKhoan:
                bundle = bundle with
                {
                    GiaoKhoan = await db.GiaoKhoanDetails.AsNoTracking()
                        .Where(d => d.ContractId == request.ContractId)
                        .OrderBy(d => d.Order)
                        .Select(d => new GiaoKhoanDetailDto(d.Id, d.Order, d.MaCongViec, d.TenCongViec, d.DonViTinh, d.KhoiLuong, d.DonGia, d.ThanhTien, d.ThoiGianHoanThanh, d.YeuCauKyThuat, d.GhiChu))
                        .ToListAsync(ct),
                };
                break;

            case ContractType.HopDongNhaCungCap:
                bundle = bundle with
                {
                    NhaCungCap = await db.NhaCungCapDetails.AsNoTracking()
                        .Where(d => d.ContractId == request.ContractId)
                        .OrderBy(d => d.Order)
                        .Select(d => new NhaCungCapDetailDto(d.Id, d.Order, d.MaSP, d.TenSP, d.ThongSoKyThuat, d.DonViTinh, d.SoLuong, d.DonGia, d.ThanhTien, d.ThoiGianGiao, d.XuatXu, d.GhiChu))
                        .ToListAsync(ct),
                };
                break;

            case ContractType.HopDongDichVu:
                bundle = bundle with
                {
                    DichVu = await db.DichVuDetails.AsNoTracking()
                        .Where(d => d.ContractId == request.ContractId)
                        .OrderBy(d => d.Order)
                        .Select(d => new DichVuDetailDto(d.Id, d.Order, d.MaDichVu, d.TenDichVu, d.MoTa, d.DonViTinh, d.ThoiGian, d.DonGia, d.ThanhTien, d.TuNgay, d.DenNgay, d.GhiChu))
                        .ToListAsync(ct),
                };
                break;

            case ContractType.HopDongMuaBan:
                bundle = bundle with
                {
                    MuaBan = await db.MuaBanDetails.AsNoTracking()
                        .Where(d => d.ContractId == request.ContractId)
                        .OrderBy(d => d.Order)
                        .Select(d => new MuaBanDetailDto(d.Id, d.Order, d.MaSP, d.TenSP, d.MoTa, d.DonViTinh, d.SoLuong, d.DonGia, d.ThueVAT, d.ThanhTien, d.XuatXu, d.GhiChu))
                        .ToListAsync(ct),
                };
                break;

            case ContractType.HopDongNguyenTacNCC:
                bundle = bundle with
                {
                    NguyenTacNcc = await db.NguyenTacNccDetails.AsNoTracking()
                        .Where(d => d.ContractId == request.ContractId)
                        .OrderBy(d => d.Order)
                        .Select(d => new NguyenTacNccDetailDto(d.Id, d.Order, d.NhomSP, d.TenSP, d.DonViTinh, d.DonGiaToiThieu, d.DonGiaToiDa, d.DieuKienGiaoHang, d.DieuKienThanhToan, d.GhiChu))
                        .ToListAsync(ct),
                };
                break;

            case ContractType.HopDongNguyenTacDichVu:
                bundle = bundle with
                {
                    NguyenTacDv = await db.NguyenTacDvDetails.AsNoTracking()
                        .Where(d => d.ContractId == request.ContractId)
                        .OrderBy(d => d.Order)
                        .Select(d => new NguyenTacDvDetailDto(d.Id, d.Order, d.LoaiDichVu, d.TenDichVu, d.DonViTinh, d.DonGiaToiThieu, d.DonGiaToiDa, d.PhamViDichVu, d.SLA, d.GhiChu))
                        .ToListAsync(ct),
                };
                break;
        }
        return bundle;
    }
}

// ========== ADD detail (per type) ==========

// Polymorphic input: client gửi Type discriminator + 1 trong 7 typed payload.
// Strategy: 7 commands riêng — explicit, dễ validate. Controller pick handler
// theo URL path /thau-phu /giao-khoan /etc, hoặc body Type field (chọn URL —
// REST hơn).

public record AddThauPhuDetailCommand(Guid ContractId, ThauPhuDetailDto Detail) : IRequest<Guid>;
public class AddThauPhuDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<AddThauPhuDetailCommand, Guid>
{
    public async Task<Guid> Handle(AddThauPhuDetailCommand cmd, CancellationToken ct)
    {
        var contract = await EnsureContractType(db, cmd.ContractId, ContractType.HopDongThauPhu, ct);
        var d = cmd.Detail;
        var entity = new ThauPhuDetail
        {
            ContractId = contract.Id, Order = d.Order, HangMuc = d.HangMuc, DonViTinh = d.DonViTinh,
            KhoiLuong = d.KhoiLuong, DonGia = d.DonGia, ThanhTien = d.ThanhTien,
            ThoiGianHoanThanh = d.ThoiGianHoanThanh, GhiChu = d.GhiChu,
        };
        db.ThauPhuDetails.Add(entity);
        await changelog.LogDetailChangeAsync(contract.Id, entity.Id, ChangelogAction.Insert,
            summary: $"Thêm hạng mục: {d.HangMuc}", phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
        return entity.Id;
    }
}

public record AddGiaoKhoanDetailCommand(Guid ContractId, GiaoKhoanDetailDto Detail) : IRequest<Guid>;
public class AddGiaoKhoanDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<AddGiaoKhoanDetailCommand, Guid>
{
    public async Task<Guid> Handle(AddGiaoKhoanDetailCommand cmd, CancellationToken ct)
    {
        var contract = await EnsureContractType(db, cmd.ContractId, ContractType.HopDongGiaoKhoan, ct);
        var d = cmd.Detail;
        var entity = new GiaoKhoanDetail
        {
            ContractId = contract.Id, Order = d.Order, MaCongViec = d.MaCongViec, TenCongViec = d.TenCongViec,
            DonViTinh = d.DonViTinh, KhoiLuong = d.KhoiLuong, DonGia = d.DonGia, ThanhTien = d.ThanhTien,
            ThoiGianHoanThanh = d.ThoiGianHoanThanh, YeuCauKyThuat = d.YeuCauKyThuat, GhiChu = d.GhiChu,
        };
        db.GiaoKhoanDetails.Add(entity);
        await changelog.LogDetailChangeAsync(contract.Id, entity.Id, ChangelogAction.Insert,
            summary: $"Thêm công việc: {d.TenCongViec}", phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
        return entity.Id;
    }
}

public record AddNhaCungCapDetailCommand(Guid ContractId, NhaCungCapDetailDto Detail) : IRequest<Guid>;
public class AddNhaCungCapDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<AddNhaCungCapDetailCommand, Guid>
{
    public async Task<Guid> Handle(AddNhaCungCapDetailCommand cmd, CancellationToken ct)
    {
        var contract = await EnsureContractType(db, cmd.ContractId, ContractType.HopDongNhaCungCap, ct);
        var d = cmd.Detail;
        var entity = new NhaCungCapDetail
        {
            ContractId = contract.Id, Order = d.Order, MaSP = d.MaSP, TenSP = d.TenSP,
            ThongSoKyThuat = d.ThongSoKyThuat, DonViTinh = d.DonViTinh, SoLuong = d.SoLuong,
            DonGia = d.DonGia, ThanhTien = d.ThanhTien, ThoiGianGiao = d.ThoiGianGiao,
            XuatXu = d.XuatXu, GhiChu = d.GhiChu,
        };
        db.NhaCungCapDetails.Add(entity);
        await changelog.LogDetailChangeAsync(contract.Id, entity.Id, ChangelogAction.Insert,
            summary: $"Thêm sản phẩm: {d.TenSP}", phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
        return entity.Id;
    }
}

public record AddDichVuDetailCommand(Guid ContractId, DichVuDetailDto Detail) : IRequest<Guid>;
public class AddDichVuDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<AddDichVuDetailCommand, Guid>
{
    public async Task<Guid> Handle(AddDichVuDetailCommand cmd, CancellationToken ct)
    {
        var contract = await EnsureContractType(db, cmd.ContractId, ContractType.HopDongDichVu, ct);
        var d = cmd.Detail;
        var entity = new DichVuDetail
        {
            ContractId = contract.Id, Order = d.Order, MaDichVu = d.MaDichVu, TenDichVu = d.TenDichVu,
            MoTa = d.MoTa, DonViTinh = d.DonViTinh, ThoiGian = d.ThoiGian, DonGia = d.DonGia,
            ThanhTien = d.ThanhTien, TuNgay = d.TuNgay, DenNgay = d.DenNgay, GhiChu = d.GhiChu,
        };
        db.DichVuDetails.Add(entity);
        await changelog.LogDetailChangeAsync(contract.Id, entity.Id, ChangelogAction.Insert,
            summary: $"Thêm dịch vụ: {d.TenDichVu}", phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
        return entity.Id;
    }
}

public record AddMuaBanDetailCommand(Guid ContractId, MuaBanDetailDto Detail) : IRequest<Guid>;
public class AddMuaBanDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<AddMuaBanDetailCommand, Guid>
{
    public async Task<Guid> Handle(AddMuaBanDetailCommand cmd, CancellationToken ct)
    {
        var contract = await EnsureContractType(db, cmd.ContractId, ContractType.HopDongMuaBan, ct);
        var d = cmd.Detail;
        var entity = new MuaBanDetail
        {
            ContractId = contract.Id, Order = d.Order, MaSP = d.MaSP, TenSP = d.TenSP,
            MoTa = d.MoTa, DonViTinh = d.DonViTinh, SoLuong = d.SoLuong, DonGia = d.DonGia,
            ThueVAT = d.ThueVAT, ThanhTien = d.ThanhTien, XuatXu = d.XuatXu, GhiChu = d.GhiChu,
        };
        db.MuaBanDetails.Add(entity);
        await changelog.LogDetailChangeAsync(contract.Id, entity.Id, ChangelogAction.Insert,
            summary: $"Thêm SP: {d.TenSP}", phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
        return entity.Id;
    }
}

public record AddNguyenTacNccDetailCommand(Guid ContractId, NguyenTacNccDetailDto Detail) : IRequest<Guid>;
public class AddNguyenTacNccDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<AddNguyenTacNccDetailCommand, Guid>
{
    public async Task<Guid> Handle(AddNguyenTacNccDetailCommand cmd, CancellationToken ct)
    {
        var contract = await EnsureContractType(db, cmd.ContractId, ContractType.HopDongNguyenTacNCC, ct);
        var d = cmd.Detail;
        var entity = new NguyenTacNccDetail
        {
            ContractId = contract.Id, Order = d.Order, NhomSP = d.NhomSP, TenSP = d.TenSP,
            DonViTinh = d.DonViTinh, DonGiaToiThieu = d.DonGiaToiThieu, DonGiaToiDa = d.DonGiaToiDa,
            DieuKienGiaoHang = d.DieuKienGiaoHang, DieuKienThanhToan = d.DieuKienThanhToan, GhiChu = d.GhiChu,
        };
        db.NguyenTacNccDetails.Add(entity);
        await changelog.LogDetailChangeAsync(contract.Id, entity.Id, ChangelogAction.Insert,
            summary: $"Thêm SP nguyên tắc: {d.TenSP}", phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
        return entity.Id;
    }
}

public record AddNguyenTacDvDetailCommand(Guid ContractId, NguyenTacDvDetailDto Detail) : IRequest<Guid>;
public class AddNguyenTacDvDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<AddNguyenTacDvDetailCommand, Guid>
{
    public async Task<Guid> Handle(AddNguyenTacDvDetailCommand cmd, CancellationToken ct)
    {
        var contract = await EnsureContractType(db, cmd.ContractId, ContractType.HopDongNguyenTacDichVu, ct);
        var d = cmd.Detail;
        var entity = new NguyenTacDvDetail
        {
            ContractId = contract.Id, Order = d.Order, LoaiDichVu = d.LoaiDichVu, TenDichVu = d.TenDichVu,
            DonViTinh = d.DonViTinh, DonGiaToiThieu = d.DonGiaToiThieu, DonGiaToiDa = d.DonGiaToiDa,
            PhamViDichVu = d.PhamViDichVu, SLA = d.SLA, GhiChu = d.GhiChu,
        };
        db.NguyenTacDvDetails.Add(entity);
        await changelog.LogDetailChangeAsync(contract.Id, entity.Id, ChangelogAction.Insert,
            summary: $"Thêm DV nguyên tắc: {d.TenDichVu}", phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
        return entity.Id;
    }
}

// ========== UPDATE detail (per type — typed) ==========
// Mỗi type có handler riêng để TS strict + validation đúng schema. Pattern
// lặp giống Add commands. ID trong URL phải khớp với detail thuộc đúng
// contract + đúng type (EnsureContractType guard).

public record UpdateThauPhuDetailCommand(Guid ContractId, Guid DetailId, ThauPhuDetailDto Detail) : IRequest;
public class UpdateThauPhuDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<UpdateThauPhuDetailCommand>
{
    public async Task Handle(UpdateThauPhuDetailCommand cmd, CancellationToken ct)
    {
        var contract = await EnsureContractType(db, cmd.ContractId, ContractType.HopDongThauPhu, ct);
        var entity = await db.ThauPhuDetails.FirstOrDefaultAsync(x => x.Id == cmd.DetailId && x.ContractId == cmd.ContractId, ct)
            ?? throw new NotFoundException("ThauPhuDetail", cmd.DetailId);
        var d = cmd.Detail;
        entity.Order = d.Order; entity.HangMuc = d.HangMuc; entity.DonViTinh = d.DonViTinh;
        entity.KhoiLuong = d.KhoiLuong; entity.DonGia = d.DonGia; entity.ThanhTien = d.ThanhTien;
        entity.ThoiGianHoanThanh = d.ThoiGianHoanThanh; entity.GhiChu = d.GhiChu;
        await changelog.LogDetailChangeAsync(contract.Id, entity.Id, ChangelogAction.Update,
            summary: $"Sửa hạng mục: {d.HangMuc}", phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
    }
}

public record UpdateGiaoKhoanDetailCommand(Guid ContractId, Guid DetailId, GiaoKhoanDetailDto Detail) : IRequest;
public class UpdateGiaoKhoanDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<UpdateGiaoKhoanDetailCommand>
{
    public async Task Handle(UpdateGiaoKhoanDetailCommand cmd, CancellationToken ct)
    {
        var contract = await EnsureContractType(db, cmd.ContractId, ContractType.HopDongGiaoKhoan, ct);
        var entity = await db.GiaoKhoanDetails.FirstOrDefaultAsync(x => x.Id == cmd.DetailId && x.ContractId == cmd.ContractId, ct)
            ?? throw new NotFoundException("GiaoKhoanDetail", cmd.DetailId);
        var d = cmd.Detail;
        entity.Order = d.Order; entity.MaCongViec = d.MaCongViec; entity.TenCongViec = d.TenCongViec;
        entity.DonViTinh = d.DonViTinh; entity.KhoiLuong = d.KhoiLuong; entity.DonGia = d.DonGia;
        entity.ThanhTien = d.ThanhTien; entity.ThoiGianHoanThanh = d.ThoiGianHoanThanh;
        entity.YeuCauKyThuat = d.YeuCauKyThuat; entity.GhiChu = d.GhiChu;
        await changelog.LogDetailChangeAsync(contract.Id, entity.Id, ChangelogAction.Update,
            summary: $"Sửa công việc: {d.TenCongViec}", phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
    }
}

public record UpdateNhaCungCapDetailCommand(Guid ContractId, Guid DetailId, NhaCungCapDetailDto Detail) : IRequest;
public class UpdateNhaCungCapDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<UpdateNhaCungCapDetailCommand>
{
    public async Task Handle(UpdateNhaCungCapDetailCommand cmd, CancellationToken ct)
    {
        var contract = await EnsureContractType(db, cmd.ContractId, ContractType.HopDongNhaCungCap, ct);
        var entity = await db.NhaCungCapDetails.FirstOrDefaultAsync(x => x.Id == cmd.DetailId && x.ContractId == cmd.ContractId, ct)
            ?? throw new NotFoundException("NhaCungCapDetail", cmd.DetailId);
        var d = cmd.Detail;
        entity.Order = d.Order; entity.MaSP = d.MaSP; entity.TenSP = d.TenSP;
        entity.ThongSoKyThuat = d.ThongSoKyThuat; entity.DonViTinh = d.DonViTinh;
        entity.SoLuong = d.SoLuong; entity.DonGia = d.DonGia; entity.ThanhTien = d.ThanhTien;
        entity.ThoiGianGiao = d.ThoiGianGiao; entity.XuatXu = d.XuatXu; entity.GhiChu = d.GhiChu;
        await changelog.LogDetailChangeAsync(contract.Id, entity.Id, ChangelogAction.Update,
            summary: $"Sửa SP: {d.TenSP}", phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
    }
}

public record UpdateDichVuDetailCommand(Guid ContractId, Guid DetailId, DichVuDetailDto Detail) : IRequest;
public class UpdateDichVuDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<UpdateDichVuDetailCommand>
{
    public async Task Handle(UpdateDichVuDetailCommand cmd, CancellationToken ct)
    {
        var contract = await EnsureContractType(db, cmd.ContractId, ContractType.HopDongDichVu, ct);
        var entity = await db.DichVuDetails.FirstOrDefaultAsync(x => x.Id == cmd.DetailId && x.ContractId == cmd.ContractId, ct)
            ?? throw new NotFoundException("DichVuDetail", cmd.DetailId);
        var d = cmd.Detail;
        entity.Order = d.Order; entity.MaDichVu = d.MaDichVu; entity.TenDichVu = d.TenDichVu;
        entity.MoTa = d.MoTa; entity.DonViTinh = d.DonViTinh; entity.ThoiGian = d.ThoiGian;
        entity.DonGia = d.DonGia; entity.ThanhTien = d.ThanhTien;
        entity.TuNgay = d.TuNgay; entity.DenNgay = d.DenNgay; entity.GhiChu = d.GhiChu;
        await changelog.LogDetailChangeAsync(contract.Id, entity.Id, ChangelogAction.Update,
            summary: $"Sửa DV: {d.TenDichVu}", phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
    }
}

public record UpdateMuaBanDetailCommand(Guid ContractId, Guid DetailId, MuaBanDetailDto Detail) : IRequest;
public class UpdateMuaBanDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<UpdateMuaBanDetailCommand>
{
    public async Task Handle(UpdateMuaBanDetailCommand cmd, CancellationToken ct)
    {
        var contract = await EnsureContractType(db, cmd.ContractId, ContractType.HopDongMuaBan, ct);
        var entity = await db.MuaBanDetails.FirstOrDefaultAsync(x => x.Id == cmd.DetailId && x.ContractId == cmd.ContractId, ct)
            ?? throw new NotFoundException("MuaBanDetail", cmd.DetailId);
        var d = cmd.Detail;
        entity.Order = d.Order; entity.MaSP = d.MaSP; entity.TenSP = d.TenSP;
        entity.MoTa = d.MoTa; entity.DonViTinh = d.DonViTinh;
        entity.SoLuong = d.SoLuong; entity.DonGia = d.DonGia;
        entity.ThueVAT = d.ThueVAT; entity.ThanhTien = d.ThanhTien;
        entity.XuatXu = d.XuatXu; entity.GhiChu = d.GhiChu;
        await changelog.LogDetailChangeAsync(contract.Id, entity.Id, ChangelogAction.Update,
            summary: $"Sửa SP: {d.TenSP}", phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
    }
}

public record UpdateNguyenTacNccDetailCommand(Guid ContractId, Guid DetailId, NguyenTacNccDetailDto Detail) : IRequest;
public class UpdateNguyenTacNccDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<UpdateNguyenTacNccDetailCommand>
{
    public async Task Handle(UpdateNguyenTacNccDetailCommand cmd, CancellationToken ct)
    {
        var contract = await EnsureContractType(db, cmd.ContractId, ContractType.HopDongNguyenTacNCC, ct);
        var entity = await db.NguyenTacNccDetails.FirstOrDefaultAsync(x => x.Id == cmd.DetailId && x.ContractId == cmd.ContractId, ct)
            ?? throw new NotFoundException("NguyenTacNccDetail", cmd.DetailId);
        var d = cmd.Detail;
        entity.Order = d.Order; entity.NhomSP = d.NhomSP; entity.TenSP = d.TenSP;
        entity.DonViTinh = d.DonViTinh; entity.DonGiaToiThieu = d.DonGiaToiThieu;
        entity.DonGiaToiDa = d.DonGiaToiDa; entity.DieuKienGiaoHang = d.DieuKienGiaoHang;
        entity.DieuKienThanhToan = d.DieuKienThanhToan; entity.GhiChu = d.GhiChu;
        await changelog.LogDetailChangeAsync(contract.Id, entity.Id, ChangelogAction.Update,
            summary: $"Sửa SP nguyên tắc: {d.TenSP}", phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
    }
}

public record UpdateNguyenTacDvDetailCommand(Guid ContractId, Guid DetailId, NguyenTacDvDetailDto Detail) : IRequest;
public class UpdateNguyenTacDvDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<UpdateNguyenTacDvDetailCommand>
{
    public async Task Handle(UpdateNguyenTacDvDetailCommand cmd, CancellationToken ct)
    {
        var contract = await EnsureContractType(db, cmd.ContractId, ContractType.HopDongNguyenTacDichVu, ct);
        var entity = await db.NguyenTacDvDetails.FirstOrDefaultAsync(x => x.Id == cmd.DetailId && x.ContractId == cmd.ContractId, ct)
            ?? throw new NotFoundException("NguyenTacDvDetail", cmd.DetailId);
        var d = cmd.Detail;
        entity.Order = d.Order; entity.LoaiDichVu = d.LoaiDichVu; entity.TenDichVu = d.TenDichVu;
        entity.DonViTinh = d.DonViTinh; entity.DonGiaToiThieu = d.DonGiaToiThieu;
        entity.DonGiaToiDa = d.DonGiaToiDa; entity.PhamViDichVu = d.PhamViDichVu;
        entity.SLA = d.SLA; entity.GhiChu = d.GhiChu;
        await changelog.LogDetailChangeAsync(contract.Id, entity.Id, ChangelogAction.Update,
            summary: $"Sửa DV nguyên tắc: {d.TenDichVu}", phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
    }
}

// ========== DELETE detail (generic — dispatch theo Type) ==========

public record DeleteContractDetailCommand(Guid ContractId, Guid DetailId) : IRequest;

public class DeleteContractDetailHandler(IApplicationDbContext db, IChangelogService changelog) : IRequestHandler<DeleteContractDetailCommand>
{
    public async Task Handle(DeleteContractDetailCommand cmd, CancellationToken ct)
    {
        var contract = await db.Contracts.AsNoTracking().FirstOrDefaultAsync(c => c.Id == cmd.ContractId, ct)
            ?? throw new NotFoundException("Contract", cmd.ContractId);
        // Lock edit guard (Phase 9 — Migration 16): chỉ Phase=DangSoanThao xóa được.
        if (contract.Phase != ContractPhase.DangSoanThao)
            throw new ConflictException($"HĐ đã trình duyệt (Phase={contract.Phase}), không thể xóa chi tiết. Phải reject để Drafter sửa lại.");

        // Dispatch xóa theo Type — tránh load tất cả 7 DbSet
        bool removed = false;
        string deletedSummary = "Xóa hạng mục";
        switch (contract.Type)
        {
            case ContractType.HopDongThauPhu:
                var t1 = await db.ThauPhuDetails.FirstOrDefaultAsync(d => d.Id == cmd.DetailId && d.ContractId == cmd.ContractId, ct);
                if (t1 != null) { db.ThauPhuDetails.Remove(t1); removed = true; deletedSummary = $"Xóa hạng mục: {t1.HangMuc}"; }
                break;
            case ContractType.HopDongGiaoKhoan:
                var t2 = await db.GiaoKhoanDetails.FirstOrDefaultAsync(d => d.Id == cmd.DetailId && d.ContractId == cmd.ContractId, ct);
                if (t2 != null) { db.GiaoKhoanDetails.Remove(t2); removed = true; deletedSummary = $"Xóa công việc: {t2.TenCongViec}"; }
                break;
            case ContractType.HopDongNhaCungCap:
                var t3 = await db.NhaCungCapDetails.FirstOrDefaultAsync(d => d.Id == cmd.DetailId && d.ContractId == cmd.ContractId, ct);
                if (t3 != null) { db.NhaCungCapDetails.Remove(t3); removed = true; deletedSummary = $"Xóa SP: {t3.TenSP}"; }
                break;
            case ContractType.HopDongDichVu:
                var t4 = await db.DichVuDetails.FirstOrDefaultAsync(d => d.Id == cmd.DetailId && d.ContractId == cmd.ContractId, ct);
                if (t4 != null) { db.DichVuDetails.Remove(t4); removed = true; deletedSummary = $"Xóa DV: {t4.TenDichVu}"; }
                break;
            case ContractType.HopDongMuaBan:
                var t5 = await db.MuaBanDetails.FirstOrDefaultAsync(d => d.Id == cmd.DetailId && d.ContractId == cmd.ContractId, ct);
                if (t5 != null) { db.MuaBanDetails.Remove(t5); removed = true; deletedSummary = $"Xóa SP: {t5.TenSP}"; }
                break;
            case ContractType.HopDongNguyenTacNCC:
                var t6 = await db.NguyenTacNccDetails.FirstOrDefaultAsync(d => d.Id == cmd.DetailId && d.ContractId == cmd.ContractId, ct);
                if (t6 != null) { db.NguyenTacNccDetails.Remove(t6); removed = true; deletedSummary = $"Xóa SP nguyên tắc: {t6.TenSP}"; }
                break;
            case ContractType.HopDongNguyenTacDichVu:
                var t7 = await db.NguyenTacDvDetails.FirstOrDefaultAsync(d => d.Id == cmd.DetailId && d.ContractId == cmd.ContractId, ct);
                if (t7 != null) { db.NguyenTacDvDetails.Remove(t7); removed = true; deletedSummary = $"Xóa DV nguyên tắc: {t7.TenDichVu}"; }
                break;
        }
        if (!removed) throw new NotFoundException("ContractDetail", cmd.DetailId);

        await changelog.LogDetailChangeAsync(contract.Id, cmd.DetailId, ChangelogAction.Delete,
            summary: deletedSummary, phaseAtChange: contract.Phase, ct: ct);
        await db.SaveChangesAsync(ct);
    }
}

// ========== Helpers ==========

internal static class ContractDetailsHelpers
{
    public static async Task<Contract> EnsureContractType(IApplicationDbContext db, Guid contractId, ContractType expectedType, CancellationToken ct)
    {
        var contract = await db.Contracts.AsNoTracking().FirstOrDefaultAsync(c => c.Id == contractId, ct)
            ?? throw new NotFoundException("Contract", contractId);
        if (contract.Type != expectedType)
            throw new ConflictException($"HĐ này thuộc loại {contract.Type}, không thể thêm chi tiết loại {expectedType}.");
        // Lock edit guard (Phase 9 — Migration 16): chỉ Phase=DangSoanThao mới
        // được CRUD chi tiết. Đã trình duyệt → KHÔNG sửa được thông tin nữa.
        if (contract.Phase != ContractPhase.DangSoanThao)
            throw new ConflictException($"HĐ đã trình duyệt (Phase={contract.Phase}), không thể chỉnh sửa chi tiết. Phải reject để Drafter sửa lại.");
        return contract;
    }
}
