using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SolutionErp.Application.Common.Models;
using SolutionErp.Application.Contracts;
using SolutionErp.Application.Contracts.Dtos;
using SolutionErp.Domain.Contracts;

namespace SolutionErp.Api.Controllers;

[ApiController]
[Route("api/contracts")]
[Authorize]
public class ContractsController(IMediator mediator) : ControllerBase
{
    [HttpGet]
    public async Task<ActionResult<PagedResult<ContractListItemDto>>> List(
        [FromQuery] int page = 1, [FromQuery] int pageSize = 20,
        [FromQuery] string? search = null, [FromQuery] bool sortDesc = true,
        [FromQuery] ContractPhase? phase = null,
        [FromQuery] Guid? supplierId = null,
        [FromQuery] Guid? projectId = null,
        // [W7 S161] Lọc theo loại HĐ cho 7 leaf bản-cứng `Hdc_*`: `?type={1..7}&phase=9`.
        // Nullable ⇒ bỏ trống = giữ nguyên hành vi cũ (0 breaking cho caller hiện có).
        [FromQuery] ContractType? type = null,
        CancellationToken ct = default)
        => Ok(await mediator.Send(new ListContractsQuery(phase, supplierId, projectId, type) { Page = page, PageSize = pageSize, Search = search, SortDesc = sortDesc }, ct));

    // [S159-đợt5] Màn "Đã xóa" HĐ (chỉ-xem) — mirror PE /deleted (S155). Read-only,
    // policy root Contracts.Read (chặt hơn [Authorize] trần của class — không phá gì).
    [HttpGet("deleted")]
    [Authorize(Policy = "Contracts.Read")]
    public async Task<ActionResult<PagedResult<ContractListItemDto>>> ListDeleted(
        [FromQuery] ContractType? type = null,
        [FromQuery] int page = 1, [FromQuery] int pageSize = 20,
        [FromQuery] string? search = null, [FromQuery] bool sortDesc = true,
        CancellationToken ct = default)
        => Ok(await mediator.Send(new ListDeletedContractsQuery(type)
        { Page = page, PageSize = pageSize, Search = search, SortDesc = sortDesc }, ct));

    [HttpGet("inbox")]
    public async Task<ActionResult<List<ContractListItemDto>>> Inbox(CancellationToken ct)
        => Ok(await mediator.Send(new GetMyInboxQuery(), ct));

    [HttpGet("{id:guid}")]
    public async Task<ActionResult<ContractDetailDto>> Get(Guid id, CancellationToken ct)
        => Ok(await mediator.Send(new GetContractQuery(id), ct));

    [HttpPost]
    public async Task<ActionResult<object>> Create([FromBody] CreateContractCommand cmd, CancellationToken ct)
    {
        var id = await mediator.Send(cmd, ct);
        return CreatedAtAction(nameof(Get), new { id }, new { id });
    }

    [HttpPut("{id:guid}")]
    public async Task<IActionResult> Update(Guid id, [FromBody] UpdateContractDraftCommand cmd, CancellationToken ct)
    {
        if (id != cmd.Id) return BadRequest(new { detail = "ID không khớp" });
        await mediator.Send(cmd, ct);
        return NoContent();
    }

    [HttpPost("{id:guid}/transitions")]
    public async Task<IActionResult> Transition(Guid id, [FromBody] TransitionContractBody body, CancellationToken ct)
    {
        // [WQ3-BE S190] `?? true` ĐẶT Ở ĐÂY (đúng khuôn KHKK): body là chỗ duy nhất phân biệt được
        // "client không gửi" ⟂ "client gửi false"; xuống tới command thì đã là `bool` dứt khoát.
        await mediator.Send(new TransitionContractCommand(
            id, body.TargetPhase, body.Decision, body.Comment,
            ApplyLevelFinalize: body.ApplyLevelFinalize ?? true,
            SkipToFinal: body.SkipToFinal), ct);
        return NoContent();
    }

    [HttpPost("{id:guid}/comments")]
    public async Task<ActionResult<object>> AddComment(Guid id, [FromBody] AddCommentBody body, CancellationToken ct)
    {
        var commentId = await mediator.Send(new AddCommentCommand(id, body.Content), ct);
        return Ok(new { id = commentId });
    }

    // [W5 S190 · YC-029] Xoá HĐ (mềm) + lý do. `reason` đi qua query-string vì verb DELETE
    // không mang body — khuôn KHKK `ContractSigningPlansController.Delete`. Optional ⇒ 0 breaking
    // cho caller cũ đang gọi `DELETE /api/contracts/{id}` không tham số.
    //
    // 🔴 CỐ Ý CHƯA gắn policy per-action cho verb này (giữ `[Authorize]` trần ở class). Đo LocalDB
    // Dev: khoá menu `Contracts` có 12/13 role `CanDelete = 0` — trong đó có chính `Drafter` ⇒ gắn
    // vào là khoá oan, người soạn mất nút xoá HĐ nháp của mình (đúng bài PE `PeSoftDeleteFeatures.cs:25-29`).
    // Rào quyền THẬT nằm ở handler (chủ HĐ hoặc Admin, xem `ContractFeatures.cs` khối DELETE) —
    // đây là chỗ duy nhất chặn được, không phải chỗ này. Mở quyền diện rộng là W8, owner đã HOÃN
    // (chốt (82)); điều kiện mở: policy + grant `Drafter` land CÙNG một commit rồi đo lại trên prod.
    // [carry:w8-delete-policy]
    [HttpDelete("{id:guid}")]
    public async Task<IActionResult> Delete(
        Guid id, [FromQuery] string? reason = null, CancellationToken ct = default)
    {
        await mediator.Send(new DeleteContractCommand(id, reason), ct);
        return NoContent();
    }

    // ==================== Attachments ====================

    // Multipart upload: file + purpose + optional note
    [HttpPost("{id:guid}/attachments")]
    [RequestSizeLimit(25_000_000)] // ~24 MB ceiling (validator enforces 20 MB)
    public async Task<ActionResult<ContractAttachmentDto>> UploadAttachment(
        Guid id,
        IFormFile file,
        [FromForm] AttachmentPurpose purpose = AttachmentPurpose.Other,
        [FromForm] string? note = null,
        CancellationToken ct = default)
    {
        if (file is null || file.Length == 0)
            return BadRequest(new { detail = "Chưa chọn file." });

        await using var stream = file.OpenReadStream();
        var dto = await mediator.Send(new UploadContractAttachmentCommand(
            id, file.FileName, file.ContentType, file.Length, stream, purpose, note), ct);
        return Ok(dto);
    }

    [HttpGet("{id:guid}/attachments/{attId:guid}/download")]
    public async Task<IActionResult> DownloadAttachment(Guid id, Guid attId, CancellationToken ct)
    {
        var file = await mediator.Send(new DownloadContractAttachmentQuery(id, attId), ct);
        return File(file.Content, file.ContentType, file.FileName);
    }

    [HttpDelete("{id:guid}/attachments/{attId:guid}")]
    public async Task<IActionResult> DeleteAttachment(Guid id, Guid attId, CancellationToken ct)
    {
        await mediator.Send(new DeleteContractAttachmentCommand(id, attId), ct);
        return NoContent();
    }

    // ========== Details (per ContractType) ==========

    [HttpGet("{id:guid}/details")]
    public async Task<ContractDetailsBundleDto> GetDetails(Guid id, CancellationToken ct)
        => await mediator.Send(new GetContractDetailsQuery(id), ct);

    [HttpPost("{id:guid}/details/thau-phu")]
    public async Task<IActionResult> AddThauPhuDetail(Guid id, [FromBody] ThauPhuDetailDto body, CancellationToken ct)
    {
        var newId = await mediator.Send(new AddThauPhuDetailCommand(id, body), ct);
        return CreatedAtAction(nameof(GetDetails), new { id }, new { id = newId });
    }

    [HttpPost("{id:guid}/details/giao-khoan")]
    public async Task<IActionResult> AddGiaoKhoanDetail(Guid id, [FromBody] GiaoKhoanDetailDto body, CancellationToken ct)
    {
        var newId = await mediator.Send(new AddGiaoKhoanDetailCommand(id, body), ct);
        return CreatedAtAction(nameof(GetDetails), new { id }, new { id = newId });
    }

    [HttpPost("{id:guid}/details/nha-cung-cap")]
    public async Task<IActionResult> AddNhaCungCapDetail(Guid id, [FromBody] NhaCungCapDetailDto body, CancellationToken ct)
    {
        var newId = await mediator.Send(new AddNhaCungCapDetailCommand(id, body), ct);
        return CreatedAtAction(nameof(GetDetails), new { id }, new { id = newId });
    }

    [HttpPost("{id:guid}/details/dich-vu")]
    public async Task<IActionResult> AddDichVuDetail(Guid id, [FromBody] DichVuDetailDto body, CancellationToken ct)
    {
        var newId = await mediator.Send(new AddDichVuDetailCommand(id, body), ct);
        return CreatedAtAction(nameof(GetDetails), new { id }, new { id = newId });
    }

    [HttpPost("{id:guid}/details/mua-ban")]
    public async Task<IActionResult> AddMuaBanDetail(Guid id, [FromBody] MuaBanDetailDto body, CancellationToken ct)
    {
        var newId = await mediator.Send(new AddMuaBanDetailCommand(id, body), ct);
        return CreatedAtAction(nameof(GetDetails), new { id }, new { id = newId });
    }

    [HttpPost("{id:guid}/details/nguyen-tac-ncc")]
    public async Task<IActionResult> AddNguyenTacNccDetail(Guid id, [FromBody] NguyenTacNccDetailDto body, CancellationToken ct)
    {
        var newId = await mediator.Send(new AddNguyenTacNccDetailCommand(id, body), ct);
        return CreatedAtAction(nameof(GetDetails), new { id }, new { id = newId });
    }

    [HttpPost("{id:guid}/details/nguyen-tac-dv")]
    public async Task<IActionResult> AddNguyenTacDvDetail(Guid id, [FromBody] NguyenTacDvDetailDto body, CancellationToken ct)
    {
        var newId = await mediator.Send(new AddNguyenTacDvDetailCommand(id, body), ct);
        return CreatedAtAction(nameof(GetDetails), new { id }, new { id = newId });
    }

    [HttpDelete("{id:guid}/details/{detailId:guid}")]
    public async Task<IActionResult> DeleteDetail(Guid id, Guid detailId, CancellationToken ct)
    {
        await mediator.Send(new DeleteContractDetailCommand(id, detailId), ct);
        return NoContent();
    }

    [HttpPut("{id:guid}/details/thau-phu/{detailId:guid}")]
    public async Task<IActionResult> UpdateThauPhuDetail(Guid id, Guid detailId, [FromBody] ThauPhuDetailDto body, CancellationToken ct)
    {
        await mediator.Send(new UpdateThauPhuDetailCommand(id, detailId, body), ct);
        return NoContent();
    }

    [HttpPut("{id:guid}/details/giao-khoan/{detailId:guid}")]
    public async Task<IActionResult> UpdateGiaoKhoanDetail(Guid id, Guid detailId, [FromBody] GiaoKhoanDetailDto body, CancellationToken ct)
    {
        await mediator.Send(new UpdateGiaoKhoanDetailCommand(id, detailId, body), ct);
        return NoContent();
    }

    [HttpPut("{id:guid}/details/nha-cung-cap/{detailId:guid}")]
    public async Task<IActionResult> UpdateNhaCungCapDetail(Guid id, Guid detailId, [FromBody] NhaCungCapDetailDto body, CancellationToken ct)
    {
        await mediator.Send(new UpdateNhaCungCapDetailCommand(id, detailId, body), ct);
        return NoContent();
    }

    [HttpPut("{id:guid}/details/dich-vu/{detailId:guid}")]
    public async Task<IActionResult> UpdateDichVuDetail(Guid id, Guid detailId, [FromBody] DichVuDetailDto body, CancellationToken ct)
    {
        await mediator.Send(new UpdateDichVuDetailCommand(id, detailId, body), ct);
        return NoContent();
    }

    [HttpPut("{id:guid}/details/mua-ban/{detailId:guid}")]
    public async Task<IActionResult> UpdateMuaBanDetail(Guid id, Guid detailId, [FromBody] MuaBanDetailDto body, CancellationToken ct)
    {
        await mediator.Send(new UpdateMuaBanDetailCommand(id, detailId, body), ct);
        return NoContent();
    }

    [HttpPut("{id:guid}/details/nguyen-tac-ncc/{detailId:guid}")]
    public async Task<IActionResult> UpdateNguyenTacNccDetail(Guid id, Guid detailId, [FromBody] NguyenTacNccDetailDto body, CancellationToken ct)
    {
        await mediator.Send(new UpdateNguyenTacNccDetailCommand(id, detailId, body), ct);
        return NoContent();
    }

    [HttpPut("{id:guid}/details/nguyen-tac-dv/{detailId:guid}")]
    public async Task<IActionResult> UpdateNguyenTacDvDetail(Guid id, Guid detailId, [FromBody] NguyenTacDvDetailDto body, CancellationToken ct)
    {
        await mediator.Send(new UpdateNguyenTacDvDetailCommand(id, detailId, body), ct);
        return NoContent();
    }

    // ========== Changelogs (read-only) ==========

    [HttpGet("{id:guid}/changelogs")]
    public async Task<List<ContractChangelogDto>> GetChangelogs(Guid id, CancellationToken ct)
        => await mediator.Send(new ListContractChangelogsQuery(id), ct);

    // 2-stage department approval list (Phase 9 — Migration 16).
    [HttpGet("{id:guid}/department-approvals")]
    public async Task<ActionResult<List<ContractDepartmentApprovalDto>>> ListDepartmentApprovals(
        Guid id, CancellationToken ct)
        => Ok(await mediator.Send(new ListContractDepartmentApprovalsQuery(id), ct));
}

// [WQ3-BE S190 · YC-030 Q3] +2 field append-CUỐI, ĐỀU có default ⇒ payload FE cũ (3 field) chạy
// y nguyên, 0 call-site vỡ.
//   • `ApplyLevelFinalize` — OPT-OUT khuôn KHKK (`ContractSigningPlansController.cs:330-333`):
//     null/true = auto kết-thúc-tại-cấp khi Cấp có `AllowApproverFinalize`; false = người duyệt bỏ
//     tick ⇒ trình tiếp. `bool?` chứ không `bool` để phân biệt "client CŨ không gửi" với "client
//     MỚI gửi false" — cả hai đều xuống service, nhưng chỉ vế đầu được hưởng mặc định true.
//   • `SkipToFinal` — cờ F2 (Mig 31) trước nay CÓ trong service mà KHÔNG có cửa API nào bật
//     (`TransitionContractCommand` cũ 4 field, handler gọi `ct:` bỏ qua) ⇒ chết câm từ S23.
public record TransitionContractBody(
    ContractPhase TargetPhase,
    ApprovalDecision Decision,
    string? Comment,
    bool? ApplyLevelFinalize = null,
    bool SkipToFinal = false);
public record AddCommentBody(string Content);
