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

namespace CashLineERP.Domain.Sales;

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

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

    public long SalesOrderId { get; private set; }

    public long SalesOrderLineId { get; private set; }

    public decimal BaseUnitPrice { get; private set; }

    public decimal RequestedUnitPrice { get; private set; }

    public decimal RequestedDiscountAmount { get; private set; }

    public decimal RequestedDiscountPercent { get; private set; }

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

    public string? Notes { get; private set; }

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

    public DateTime SubmittedAtUtc { get; private set; }

    public long SubmittedByUserId { get; private set; }

    public DateTime? DecidedAtUtc { get; private set; }

    public long? DecidedByUserId { get; private set; }

    public string? DecisionCode { get; private set; }

    public string? DecisionNotes { get; private set; }

    public SalesDiscountOverride(
        string overrideNumber,
        long salesOrderId,
        long salesOrderLineId,
        decimal baseUnitPrice,
        decimal requestedUnitPrice,
        string reasonCode,
        string? notes,
        long actorUserId,
        decimal orderedQuantity)
    {
        if (requestedUnitPrice <= 0m)
        {
            throw new InvalidOperationException("Requested discount override unit price must be greater than zero.");
        }

        if (requestedUnitPrice >= baseUnitPrice)
        {
            throw new InvalidOperationException("Discount override unit price must be lower than the base sales price.");
        }

        OverrideNumber = overrideNumber;
        SalesOrderId = salesOrderId;
        SalesOrderLineId = salesOrderLineId;
        BaseUnitPrice = baseUnitPrice;
        RequestedUnitPrice = requestedUnitPrice;
        RequestedDiscountAmount = Math.Round((baseUnitPrice - requestedUnitPrice) * orderedQuantity, 2, MidpointRounding.AwayFromZero);
        RequestedDiscountPercent = baseUnitPrice == 0m
            ? 0m
            : Math.Round(((baseUnitPrice - requestedUnitPrice) / baseUnitPrice) * 100m, 4, MidpointRounding.AwayFromZero);
        ReasonCode = reasonCode;
        Notes = notes;
        SubmittedAtUtc = DateTime.UtcNow;
        SubmittedByUserId = actorUserId;
    }

    private SalesDiscountOverride()
    {
    }

    public void Approve(long actorUserId, string? decisionNotes)
    {
        if (StatusId != WorkflowStatusSeedIds.Submitted)
        {
            throw new InvalidOperationException("Only submitted discount overrides can be approved.");
        }

        if (SubmittedByUserId == actorUserId)
        {
            throw new InvalidOperationException("Discount override maker-checker control prohibits self-approval.");
        }

        StatusId = WorkflowStatusSeedIds.Approved;
        DecidedAtUtc = DateTime.UtcNow;
        DecidedByUserId = actorUserId;
        DecisionCode = "APPROVED";
        DecisionNotes = decisionNotes;
        Touch(actorUserId);
    }

    public void Reject(long actorUserId, string? decisionNotes)
    {
        if (StatusId != WorkflowStatusSeedIds.Submitted)
        {
            throw new InvalidOperationException("Only submitted discount overrides can be rejected.");
        }

        if (SubmittedByUserId == actorUserId)
        {
            throw new InvalidOperationException("Discount override maker-checker control prohibits self-rejection.");
        }

        StatusId = WorkflowStatusSeedIds.Rejected;
        DecidedAtUtc = DateTime.UtcNow;
        DecidedByUserId = actorUserId;
        DecisionCode = "REJECTED";
        DecisionNotes = decisionNotes;
        Touch(actorUserId);
    }
}
