using TakeoutSaaS.Application.App.Finance.Invoice.Commands;
using TakeoutSaaS.Application.App.Finance.Invoice.Dto;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Domain.Tenants.Repositories;

namespace TakeoutSaaS.Application.App.Finance.Invoice;

/// <summary>
/// 发票模块 DTO 构造器。
/// </summary>
internal static class FinanceInvoiceDtoFactory
{
    public static FinanceInvoiceSettingDto CreateDefaultSettingDto()
    {
        return new FinanceInvoiceSettingDto
        {
            CompanyName = string.Empty,
            TaxpayerNumber = string.Empty,
            RegisteredAddress = null,
            RegisteredPhone = null,
            BankName = null,
            BankAccount = null,
            EnableElectronicNormalInvoice = true,
            EnableElectronicSpecialInvoice = false,
            EnableAutoIssue = false,
            AutoIssueMaxAmount = 10_000m
        };
    }

    public static FinanceInvoiceSettingDto ToSettingDto(TenantInvoiceSetting source)
    {
        return new FinanceInvoiceSettingDto
        {
            CompanyName = source.CompanyName,
            TaxpayerNumber = source.TaxpayerNumber,
            RegisteredAddress = source.RegisteredAddress,
            RegisteredPhone = source.RegisteredPhone,
            BankName = source.BankName,
            BankAccount = source.BankAccount,
            EnableElectronicNormalInvoice = source.EnableElectronicNormalInvoice,
            EnableElectronicSpecialInvoice = source.EnableElectronicSpecialInvoice,
            EnableAutoIssue = source.EnableAutoIssue,
            AutoIssueMaxAmount = decimal.Round(source.AutoIssueMaxAmount, 2, MidpointRounding.AwayFromZero)
        };
    }

    public static TenantInvoiceSetting CreateSettingEntity(
        SaveFinanceInvoiceSettingCommand request,
        string companyName,
        string taxpayerNumber,
        string? registeredAddress,
        string? registeredPhone,
        string? bankName,
        string? bankAccount,
        decimal autoIssueMaxAmount)
    {
        return new TenantInvoiceSetting
        {
            CompanyName = companyName,
            TaxpayerNumber = taxpayerNumber,
            RegisteredAddress = registeredAddress,
            RegisteredPhone = registeredPhone,
            BankName = bankName,
            BankAccount = bankAccount,
            EnableElectronicNormalInvoice = request.EnableElectronicNormalInvoice,
            EnableElectronicSpecialInvoice = request.EnableElectronicSpecialInvoice,
            EnableAutoIssue = request.EnableAutoIssue,
            AutoIssueMaxAmount = autoIssueMaxAmount
        };
    }

    public static void ApplySettingChanges(
        TenantInvoiceSetting entity,
        SaveFinanceInvoiceSettingCommand request,
        string companyName,
        string taxpayerNumber,
        string? registeredAddress,
        string? registeredPhone,
        string? bankName,
        string? bankAccount,
        decimal autoIssueMaxAmount)
    {
        entity.CompanyName = companyName;
        entity.TaxpayerNumber = taxpayerNumber;
        entity.RegisteredAddress = registeredAddress;
        entity.RegisteredPhone = registeredPhone;
        entity.BankName = bankName;
        entity.BankAccount = bankAccount;
        entity.EnableElectronicNormalInvoice = request.EnableElectronicNormalInvoice;
        entity.EnableElectronicSpecialInvoice = request.EnableElectronicSpecialInvoice;
        entity.EnableAutoIssue = request.EnableAutoIssue;
        entity.AutoIssueMaxAmount = autoIssueMaxAmount;
    }

    public static FinanceInvoiceStatsDto ToStatsDto(TenantInvoiceRecordStatsSnapshot source)
    {
        return new FinanceInvoiceStatsDto
        {
            CurrentMonthIssuedAmount = decimal.Round(source.CurrentMonthIssuedAmount, 2, MidpointRounding.AwayFromZero),
            CurrentMonthIssuedCount = source.CurrentMonthIssuedCount,
            PendingCount = source.PendingCount,
            VoidedCount = source.VoidedCount
        };
    }

    public static FinanceInvoiceRecordDto ToRecordDto(TenantInvoiceRecord source)
    {
        return new FinanceInvoiceRecordDto
        {
            RecordId = source.Id,
            InvoiceNo = source.InvoiceNo,
            ApplicantName = source.ApplicantName,
            CompanyName = source.CompanyName,
            InvoiceType = FinanceInvoiceMapping.ToInvoiceTypeText(source.InvoiceType),
            InvoiceTypeText = FinanceInvoiceMapping.ToInvoiceTypeDisplayText(source.InvoiceType),
            Amount = decimal.Round(source.Amount, 2, MidpointRounding.AwayFromZero),
            OrderNo = source.OrderNo,
            Status = FinanceInvoiceMapping.ToStatusText(source.Status),
            StatusText = FinanceInvoiceMapping.ToStatusDisplayText(source.Status),
            AppliedAt = source.AppliedAt
        };
    }

    public static FinanceInvoiceRecordDetailDto ToRecordDetailDto(TenantInvoiceRecord source)
    {
        return new FinanceInvoiceRecordDetailDto
        {
            RecordId = source.Id,
            InvoiceNo = source.InvoiceNo,
            ApplicantName = source.ApplicantName,
            CompanyName = source.CompanyName,
            TaxpayerNumber = source.TaxpayerNumber,
            InvoiceType = FinanceInvoiceMapping.ToInvoiceTypeText(source.InvoiceType),
            InvoiceTypeText = FinanceInvoiceMapping.ToInvoiceTypeDisplayText(source.InvoiceType),
            Amount = decimal.Round(source.Amount, 2, MidpointRounding.AwayFromZero),
            OrderNo = source.OrderNo,
            ContactEmail = source.ContactEmail,
            ContactPhone = source.ContactPhone,
            ApplyRemark = source.ApplyRemark,
            Status = FinanceInvoiceMapping.ToStatusText(source.Status),
            StatusText = FinanceInvoiceMapping.ToStatusDisplayText(source.Status),
            AppliedAt = source.AppliedAt,
            IssuedAt = source.IssuedAt,
            IssuedByUserId = source.IssuedByUserId,
            IssueRemark = source.IssueRemark,
            VoidedAt = source.VoidedAt,
            VoidedByUserId = source.VoidedByUserId,
            VoidReason = source.VoidReason
        };
    }

    public static FinanceInvoiceIssueResultDto ToIssueResultDto(TenantInvoiceRecord source)
    {
        return new FinanceInvoiceIssueResultDto
        {
            RecordId = source.Id,
            InvoiceNo = source.InvoiceNo,
            CompanyName = source.CompanyName,
            Amount = decimal.Round(source.Amount, 2, MidpointRounding.AwayFromZero),
            ContactEmail = source.ContactEmail,
            IssuedAt = source.IssuedAt ?? DateTime.UtcNow,
            Status = FinanceInvoiceMapping.ToStatusText(source.Status),
            StatusText = FinanceInvoiceMapping.ToStatusDisplayText(source.Status)
        };
    }

    public static TenantInvoiceRecord CreateRecordEntity(
        long tenantId,
        string invoiceNo,
        string applicantName,
        string companyName,
        string? taxpayerNumber,
        TenantInvoiceType invoiceType,
        decimal amount,
        string orderNo,
        string? contactEmail,
        string? contactPhone,
        string? applyRemark,
        DateTime appliedAt)
    {
        return new TenantInvoiceRecord
        {
            TenantId = tenantId,
            InvoiceNo = invoiceNo,
            ApplicantName = applicantName,
            CompanyName = companyName,
            TaxpayerNumber = taxpayerNumber,
            InvoiceType = invoiceType,
            Amount = amount,
            OrderNo = orderNo,
            ContactEmail = contactEmail,
            ContactPhone = contactPhone,
            ApplyRemark = applyRemark,
            Status = TenantInvoiceStatus.Pending,
            AppliedAt = appliedAt
        };
    }
}
