using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using Tiku.Application.Commerce;
using Tiku.Domain.Commerce;
using Tiku.Domain.Common;
using Tiku.Domain.Tenancy;

namespace Tiku.Api.Contracts;

public sealed class TenantCommerceQueryDto
{
    [StringLength(50)]
    public string? Provider { get; set; }

    [StringLength(32)]
    public string? Status { get; set; }

    [Range(1, 200)]
    public int? Limit { get; set; }

    public Guid? UserId { get; set; }

    public Guid? RegionId { get; set; }
}

public sealed class UpsertPaymentAccountDto
{
    [Required]
    [StringLength(50)]
    public string Provider { get; set; } = string.Empty;

    [StringLength(50)]
    public string? Mode { get; set; } = "TenantCollect";

    [StringLength(200)]
    public string? DisplayName { get; set; }

    public TenantExternalProviderStatus Status { get; set; } = TenantExternalProviderStatus.Disabled;

    [StringLength(300)]
    public string? SecretRef { get; set; }

    public int? Priority { get; set; }

    public JsonElement ConfigPublic { get; set; } = JsonDefaults.Object();

    public UpsertPaymentAccountCommand ToCommand()
    {
        return new UpsertPaymentAccountCommand(Provider, Mode, DisplayName, Status, SecretRef, Priority, ConfigPublic);
    }
}

public sealed class UpsertTenantSecretDto
{
    [Required]
    [StringLength(80)]
    public string Purpose { get; set; } = "payment";

    [Required]
    [StringLength(50)]
    public string Provider { get; set; } = string.Empty;

    [Required]
    [StringLength(120)]
    public string SecretKey { get; set; } = string.Empty;

    [StringLength(300)]
    public string SecretRef { get; set; } = string.Empty;

    public TenantSecretStatus Status { get; set; } = TenantSecretStatus.Active;
    public JsonElement SecretPayload { get; set; } = JsonDefaults.Object();
    public DateTimeOffset? ExpiresAt { get; set; }

    public UpsertTenantSecretCommand ToCommand()
    {
        return new UpsertTenantSecretCommand(
            Purpose,
            Provider,
            SecretKey,
            SecretRef,
            Status,
            SecretPayload,
            ExpiresAt);
    }
}

public sealed class CreateCodeBatchDto
{
    [Required]
    [StringLength(200)]
    public string Name { get; set; } = string.Empty;

    [Range(1, 1000)]
    public int TotalCount { get; set; }

    [Range(1, 3650)]
    public int Days { get; set; }

    public Guid? RegionId { get; set; }

    [StringLength(50)]
    public string? SaleType { get; set; }

    [StringLength(100)]
    public string? Channel { get; set; }

    [Range(0, int.MaxValue)]
    public int? DefaultUnitPriceCents { get; set; }

    [Range(0, int.MaxValue)]
    public int? CostPriceCents { get; set; }

    [StringLength(1000)]
    public string? Remark { get; set; }

    public CreateCodeBatchCommand ToCommand()
    {
        return new CreateCodeBatchCommand(
            Name,
            TotalCount,
            Days,
            RegionId,
            SaleType,
            Channel,
            DefaultUnitPriceCents,
            CostPriceCents,
            Remark);
    }
}

public sealed class RedeemActivationCodeDto
{
    [Required]
    [StringLength(100)]
    public string Code { get; set; } = string.Empty;

    [Required]
    public Guid UserId { get; set; }

    public Guid? RegionId { get; set; }

    public RedeemActivationCodeCommand ToCommand()
    {
        return new RedeemActivationCodeCommand(Code, UserId, RegionId);
    }
}

public sealed class UpsertPointTaskDto
{
    public Guid? Id { get; set; }

    [Required]
    [StringLength(100)]
    public string TaskKey { get; set; } = string.Empty;

    [Required]
    [StringLength(200)]
    public string Title { get; set; } = string.Empty;

    [StringLength(1000)]
    public string? Description { get; set; }

    public PointActivityTaskType TaskType { get; set; } = PointActivityTaskType.Manual;
    public PointActivityTaskStatus Status { get; set; } = PointActivityTaskStatus.Active;

    [Range(1, int.MaxValue)]
    public int Points { get; set; }

    [Range(1, 1000)]
    public int MaxClaimsPerUser { get; set; } = 1;

    public DateTimeOffset? StartsAt { get; set; }
    public DateTimeOffset? EndsAt { get; set; }
    public int SortOrder { get; set; }
    public JsonElement Rules { get; set; } = JsonDefaults.Object();
    public JsonElement Metadata { get; set; } = JsonDefaults.Object();

    public UpsertPointTaskCommand ToCommand()
    {
        return new UpsertPointTaskCommand(
            Id,
            TaskKey,
            Title,
            Description,
            TaskType,
            Status,
            Points,
            MaxClaimsPerUser,
            StartsAt,
            EndsAt,
            SortOrder,
            Rules,
            Metadata);
    }
}

public sealed class UpsertPointExchangeItemDto
{
    public Guid? Id { get; set; }
    public Guid? RegionId { get; set; }

    [Required]
    [StringLength(100)]
    public string ItemKey { get; set; } = string.Empty;

    [Required]
    [StringLength(200)]
    public string Name { get; set; } = string.Empty;

    [StringLength(1000)]
    public string? Description { get; set; }

    public PointExchangeItemType ItemType { get; set; } = PointExchangeItemType.Entitlement;
    public PointExchangeItemStatus Status { get; set; } = PointExchangeItemStatus.Active;

    [Range(1, int.MaxValue)]
    public int PointsCost { get; set; }

    [Range(0, int.MaxValue)]
    public int? Stock { get; set; }

    [Range(0, 3650)]
    public int? Days { get; set; }

    public int SortOrder { get; set; }
    public DateTimeOffset? StartsAt { get; set; }
    public DateTimeOffset? EndsAt { get; set; }
    public JsonElement FulfillmentPayload { get; set; } = JsonDefaults.Object();
    public JsonElement Metadata { get; set; } = JsonDefaults.Object();

    public UpsertPointExchangeItemCommand ToCommand()
    {
        return new UpsertPointExchangeItemCommand(
            Id,
            RegionId,
            ItemKey,
            Name,
            Description,
            ItemType,
            Status,
            PointsCost,
            Stock,
            Days,
            SortOrder,
            StartsAt,
            EndsAt,
            FulfillmentPayload,
            Metadata);
    }
}

public sealed class CreateRefundRequestDto
{
    [Required]
    public Guid OrderId { get; set; }

    public Guid? PaymentId { get; set; }

    [Range(1, int.MaxValue)]
    public int AmountCents { get; set; }

    [StringLength(1000)]
    public string? Reason { get; set; }

    public RefundEntitlementAction EntitlementAction { get; set; } = RefundEntitlementAction.RevokeOnSuccess;
    public JsonElement Metadata { get; set; } = JsonDefaults.Object();

    public CreateRefundRequestCommand ToCommand()
    {
        return new CreateRefundRequestCommand(OrderId, PaymentId, AmountCents, Reason, EntitlementAction, Metadata);
    }
}

public sealed class UpdateRefundStatusDto
{
    [Required]
    public Guid RefundRequestId { get; set; }

    public CommerceRefundStatus Status { get; set; }

    [StringLength(1000)]
    public string? Reason { get; set; }

    [StringLength(200)]
    public string? ProviderRefundNo { get; set; }

    public UpdateRefundStatusCommand ToCommand()
    {
        return new UpdateRefundStatusCommand(RefundRequestId, Status, Reason, ProviderRefundNo);
    }
}

public sealed class CreateReconciliationBatchDto
{
    [Required]
    [StringLength(50)]
    public string Provider { get; set; } = string.Empty;

    public DateOnly BillDate { get; set; }
    public ReconciliationBillType BillType { get; set; } = ReconciliationBillType.Combined;
    public ReconciliationSource Source { get; set; } = ReconciliationSource.ManualUpload;

    [StringLength(200)]
    public string? SourceName { get; set; }

    [Required]
    [StringLength(200)]
    public string SourceHash { get; set; } = string.Empty;

    public JsonElement Metadata { get; set; } = JsonDefaults.Object();

    public CreateReconciliationBatchCommand ToCommand()
    {
        return new CreateReconciliationBatchCommand(Provider, BillDate, BillType, Source, SourceName, SourceHash, Metadata);
    }
}

public sealed class UpdateReconciliationIssueDto
{
    [Required]
    public Guid IssueId { get; set; }

    public ReconciliationIssueStatus Status { get; set; } = ReconciliationIssueStatus.Investigating;
    public ReconciliationResolutionType ResolutionType { get; set; } = ReconciliationResolutionType.None;

    [StringLength(1000)]
    public string? Note { get; set; }

    public Guid? AssignedTo { get; set; }

    public UpdateReconciliationIssueCommand ToCommand()
    {
        return new UpdateReconciliationIssueCommand(IssueId, Status, ResolutionType, Note, AssignedTo);
    }
}

public sealed class PreviewReconciliationImportDto
{
    [Required]
    [StringLength(50)]
    public string Provider { get; set; } = string.Empty;

    public DateOnly BillDate { get; set; }
    public ReconciliationBillType BillType { get; set; } = ReconciliationBillType.Combined;

    [Required]
    [StringLength(300)]
    public string SourceName { get; set; } = string.Empty;

    public JsonElement Rows { get; set; } = JsonDefaults.Array();

    public PreviewReconciliationImportCommand ToPreviewCommand() => new(Provider, BillDate, BillType, SourceName, Rows);

    public ImportReconciliationCommand ToImportCommand() => new(Provider, BillDate, BillType, SourceName, Rows);
}

public sealed class CreateAdjustmentVoucherDto
{
    public Guid? IssueId { get; set; }
    public Guid? BatchId { get; set; }
    public Guid? ItemId { get; set; }
    public Guid? OrderId { get; set; }
    public Guid? PaymentId { get; set; }
    public Guid? RefundRequestId { get; set; }
    public CommerceAdjustmentDirection Direction { get; set; } = CommerceAdjustmentDirection.IncreaseRevenue;

    [Range(1, int.MaxValue)]
    public int AmountCents { get; set; }

    [StringLength(10)]
    public string? Currency { get; set; }

    [Required]
    [StringLength(1000)]
    public string Reason { get; set; } = string.Empty;

    [StringLength(500)]
    public string? ProofAssetKey { get; set; }

    public JsonElement Metadata { get; set; } = JsonDefaults.Object();

    public CreateAdjustmentVoucherCommand ToCommand() => new(
        IssueId,
        BatchId,
        ItemId,
        OrderId,
        PaymentId,
        RefundRequestId,
        Direction,
        AmountCents,
        Currency,
        Reason,
        ProofAssetKey,
        Metadata);
}

public sealed class UpdateAdjustmentVoucherStatusDto
{
    [Required]
    public Guid VoucherId { get; set; }

    public CommerceAdjustmentVoucherStatus Status { get; set; } = CommerceAdjustmentVoucherStatus.PendingReview;

    [StringLength(1000)]
    public string? Note { get; set; }

    public UpdateAdjustmentVoucherStatusCommand ToCommand() => new(VoucherId, Status, Note);
}

public sealed class RequestProviderBillJobDto
{
    [Required]
    [StringLength(50)]
    public string Provider { get; set; } = string.Empty;

    public DateOnly BillDate { get; set; }
    public ReconciliationBillType BillType { get; set; } = ReconciliationBillType.Combined;
    public DateTimeOffset? RunAfter { get; set; }

    public RequestProviderBillJobCommand ToCommand() => new(Provider, BillDate, BillType, RunAfter);
}

public sealed class RefundNotificationDto
{
    [Required]
    [StringLength(100)]
    public string RefundNo { get; set; } = string.Empty;

    [StringLength(200)]
    public string? ProviderRefundNo { get; set; }

    public CommerceRefundStatus Status { get; set; } = CommerceRefundStatus.Succeeded;

    [StringLength(200)]
    public string? EventId { get; set; }

    public JsonElement Payload { get; set; } = JsonDefaults.Object();

    public RefundNotificationCommand ToCommand(string provider) => new(provider, RefundNo, ProviderRefundNo, Status, EventId, Payload);
}

public sealed class UpdatePointExchangeOrderStatusDto
{
    [Required]
    public Guid OrderId { get; set; }

    public PointExchangeOrderStatus Status { get; set; }

    public UpdatePointExchangeOrderStatusCommand ToCommand()
    {
        return new UpdatePointExchangeOrderStatusCommand(OrderId, Status);
    }
}

public sealed class UpsertTenantCouponDto
{
    public Guid? Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Code { get; set; } = string.Empty;

    public Guid? PlanId { get; set; }
    public DiscountType DiscountType { get; set; } = DiscountType.Fixed;

    [Range(typeof(decimal), "0.01", "999999")]
    public decimal DiscountValue { get; set; }

    public DateTimeOffset? ValidFrom { get; set; }
    public DateTimeOffset? ValidTo { get; set; }

    [Range(1, int.MaxValue)]
    public int? MaxUses { get; set; }

    [StringLength(50)]
    public string? Source { get; set; }

    [StringLength(1000)]
    public string? Remark { get; set; }

    public UpsertCouponCommand ToCommand()
    {
        return new UpsertCouponCommand(
            Id,
            Code,
            PlanId,
            DiscountType,
            DiscountValue,
            ValidFrom,
            ValidTo,
            MaxUses,
            Source,
            Remark);
    }
}
