using Tiku.Api.Middleware;
using Tiku.Application.Commerce;
using Tiku.Application.Growth;
using Tiku.Application.Points;

namespace Tiku.Api.Modules.Tenant.Commerce.Errors;

internal sealed class CommerceExceptionProblemDetailsMapper : ExceptionProblemDetailsMapper
{
    public override IReadOnlyCollection<Type> HandledExceptionTypes { get; } =
    [
        typeof(CommerceException), typeof(PointException), typeof(ReferralException), typeof(CrmException),
        typeof(CommissionException), typeof(PaymentProviderException)
    ];

    public override bool TryMap(Exception exception, out ExceptionProblemDetailsMapping mapping)
    {
        return exception switch
        {
            CommerceException commerce => Mapped(commerce, CommerceStatus(commerce.Code), commerce.Code, out mapping),
            PaymentProviderException provider => Mapped(provider, CommerceStatus(provider.Code), provider.Code,
                out mapping),
            PointException point => Mapped(point, PointStatus(point.Code), point.Code, out mapping),
            ReferralException referral => Mapped(referral, ReferralStatus(referral.Code), referral.Code, out mapping),
            CrmException crm => Mapped(crm, CrmStatus(crm.Code), crm.Code, out mapping),
            CommissionException commission => Mapped(commission, CommissionStatus(commission.Code), commission.Code,
                out mapping),
            _ => NotMapped(out mapping)
        };
    }

    private static int CommerceStatus(string code) => code switch
    {
        "commerce_access_denied" or "tenant_access_denied" or "tenant_admin_access_denied" =>
            StatusCodes.Status403Forbidden,
        "order_not_found" or "svip_plan_not_found" or "region_not_found" or "activation_code_not_found" or
            "coupon_not_found" or "coupon_redemption_not_found" => StatusCodes.Status404NotFound,
        "payment_provider_not_configured" or "payment_secret_not_configured" =>
            StatusCodes.Status503ServiceUnavailable,
        "order_status_invalid" or "activation_code_used" or "payment_amount_mismatch" or
            "coupon_usage_limit_reached" or "coupon_redemption_status_invalid" => StatusCodes.Status409Conflict,
        _ when code.EndsWith("_not_found", StringComparison.Ordinal) => StatusCodes.Status404NotFound,
        _ => StatusCodes.Status400BadRequest
    };

    private static int PointStatus(string code) => code switch
    {
        "point_access_denied" or "tenant_access_denied" => StatusCodes.Status403Forbidden,
        "point_task_not_found" or "point_exchange_item_not_found" => StatusCodes.Status404NotFound,
        "point_task_claim_limit_reached" or "insufficient_points" or "point_exchange_item_sold_out" =>
            StatusCodes.Status409Conflict,
        _ => StatusCodes.Status400BadRequest
    };

    private static int ReferralStatus(string code) => code switch
    {
        "referral_access_denied" or "tenant_access_denied" => StatusCodes.Status403Forbidden,
        "referral_code_not_found" => StatusCodes.Status404NotFound,
        "referral_lead_protected" or "self_referral_not_allowed" => StatusCodes.Status409Conflict,
        _ => StatusCodes.Status400BadRequest
    };

    private static int CrmStatus(string code) => code switch
    {
        "crm_access_denied" => StatusCodes.Status403Forbidden,
        "crm_queue_not_found" => StatusCodes.Status404NotFound,
        "crm_queue_status_invalid" => StatusCodes.Status409Conflict,
        _ => StatusCodes.Status400BadRequest
    };

    private static int CommissionStatus(string code) => code switch
    {
        "commission_access_denied" => StatusCodes.Status403Forbidden,
        "commission_member_not_found" or "commission_settlement_not_found" or "commission_proof_not_found" =>
            StatusCodes.Status404NotFound,
        "commission_no_unsettled_sources" or "commission_below_minimum" or "commission_status_invalid" or
            "commission_proof_closed" => StatusCodes.Status409Conflict,
        _ => StatusCodes.Status400BadRequest
    };
}
