using CashLineERP.Domain.Common;
using CashLineERP.SharedKernel.Workflow;

namespace CashLineERP.Domain.Procurement;

public sealed class PurchaseOrder : Entity
{
    public long Id { get; private set; }

    public string PurchaseOrderNumber { get; private set; } = string.Empty;

    public long BranchId { get; private set; }

    public long SupplierId { get; private set; }

    public long? PurchaseRequisitionId { get; private set; }

    public DateOnly PurchaseOrderDate { get; private set; }

    public string CurrencyCode { get; private set; } = "EGP";

    public decimal ExchangeRate { get; private set; } = 1m;

    public long StatusId { get; private set; } = WorkflowStatusSeedIds.Draft;

    public decimal SubtotalAmount { get; private set; }

    public decimal TaxAmount { get; private set; }

    public decimal TotalAmount { get; private set; }

    public string? SupplierAcknowledgmentStatusCode { get; private set; }

    public DateTime? SupplierAcknowledgedAtUtc { get; private set; }

    public long? SupplierAcknowledgedByUserId { get; private set; }

    public string? SupplierAcknowledgmentNotes { get; private set; }

    public List<PurchaseOrderLine> Lines { get; private set; } = [];

    public PurchaseOrder(
        string purchaseOrderNumber,
        long branchId,
        long supplierId,
        long? purchaseRequisitionId,
        DateOnly purchaseOrderDate,
        string currencyCode,
        decimal exchangeRate)
    {
        PurchaseOrderNumber = purchaseOrderNumber;
        BranchId = branchId;
        SupplierId = supplierId;
        PurchaseRequisitionId = purchaseRequisitionId;
        PurchaseOrderDate = purchaseOrderDate;
        CurrencyCode = currencyCode;
        ExchangeRate = exchangeRate;
    }

    private PurchaseOrder()
    {
    }

    public void AddLine(
        int lineNumber,
        long itemId,
        long warehouseId,
        decimal orderedQuantity,
        string unitOfMeasureCode,
        decimal unitPrice,
        string? taxCode)
    {
        Lines.Add(new PurchaseOrderLine(
            purchaseOrderId: Id,
            lineNumber: lineNumber,
            itemId: itemId,
            warehouseId: warehouseId,
            orderedQuantity: orderedQuantity,
            unitOfMeasureCode: unitOfMeasureCode,
            unitPrice: unitPrice,
            taxCode: taxCode));

        RecalculateTotals();
    }

    public void Approve(long actorUserId)
    {
        StatusId = WorkflowStatusSeedIds.Approved;
        Touch(actorUserId);
    }

    public void AcknowledgeBySupplier(long actorUserId, string acknowledgmentStatusCode, string? notes)
    {
        if (string.IsNullOrWhiteSpace(acknowledgmentStatusCode))
        {
            throw new InvalidOperationException("Supplier acknowledgment status code is required.");
        }

        if (StatusId == WorkflowStatusSeedIds.Draft)
        {
            throw new InvalidOperationException("Supplier acknowledgment requires a submitted or approved purchase order.");
        }

        SupplierAcknowledgmentStatusCode = acknowledgmentStatusCode.Trim().ToUpperInvariant();
        SupplierAcknowledgedAtUtc = DateTime.UtcNow;
        SupplierAcknowledgedByUserId = actorUserId;
        SupplierAcknowledgmentNotes = string.IsNullOrWhiteSpace(notes) ? null : notes.Trim();
        Touch(actorUserId);
    }

    private void RecalculateTotals()
    {
        SubtotalAmount = Lines.Sum(line => line.LineNetAmount);
        TaxAmount = Lines.Sum(line => line.LineTaxAmount);
        TotalAmount = Lines.Sum(line => line.LineTotalAmount);
    }
}
