namespace KArtSell.Modules.SignalEngine.Domain.Policies;

public sealed class OpportunityCostPolicy : ISellPolicy
{
    public int Priority => SellPolicyContract.OpportunityCostPriority;
    public string PolicyId => SellPolicyContract.OpportunityCostPolicyId;

    public SellPolicyResult Evaluate(SellDecisionInput input)
    {
        if (input.OpportunityEdgeLowerBound <= 0m)
        {
            return SellPolicyResult.NotApplicable(PolicyId, Priority, "EDGE_LOWER_BOUND_NOT_POSITIVE");
        }

        if (input.OpportunitySellRatioOfLot <= 0m)
        {
            return SellPolicyResult.Blocked(PolicyId, Priority, "OPPORTUNITY_RATIO_NOT_POSITIVE");
        }

        var requested = Math.Clamp(
            input.OpportunitySellRatioOfLot,
            SellPolicyContract.OpportunityMinimumSellRatioOfLot,
            SellPolicyContract.OpportunityMaximumSellRatioOfLot);

        if (!input.CooldownSatisfied)
        {
            return SellPolicyResult.Blocked(PolicyId, Priority, "COOLDOWN_NOT_SATISFIED", requested);
        }

        var max = input.MaxSellRatioPreservingStrategicCore();
        var applied = Math.Min(requested, max);
        if (applied <= 0m)
        {
            return SellPolicyResult.Blocked(PolicyId, Priority, "STRATEGIC_CORE_BLOCKED", requested);
        }

        var decision = new SellDecision(
            SellAction.PartialSell,
            applied,
            input.TargetSecurityPortfolioWeightAfter(applied),
            PolicyId,
            Priority,
            "OPPORTUNITY_REPLACEMENT",
            input.EvidenceId,
            input.DatasetId,
            input.ModelVersion,
            input.ConfigVersion,
            input.CodeSha,
            true,
            Array.Empty<PolicyTraceEntry>());
        return SellPolicyResult.Applied(decision, requested, applied < requested);
    }
}
