using System.Globalization;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using TakeoutSaaS.Application.App.Finance.Invoice.Commands;
using TakeoutSaaS.Application.App.Finance.Invoice.Dto;
using TakeoutSaaS.Application.App.Finance.Invoice.Queries;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Module.Authorization.Attributes;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Results;
using TakeoutSaaS.Shared.Web.Api;
using TakeoutSaaS.TenantApi.Contracts.Finance;

namespace TakeoutSaaS.TenantApi.Controllers;

/// <summary>
/// 财务中心发票管理。
/// </summary>
[ApiVersion("1.0")]
[Authorize]
[Route("api/tenant/v{version:apiVersion}/finance/invoice")]
public sealed class FinanceInvoiceController(IMediator mediator) : BaseApiController
{
    private const string ViewPermission = "tenant:finance:invoice:view";
    private const string IssuePermission = "tenant:finance:invoice:issue";
    private const string VoidPermission = "tenant:finance:invoice:void";
    private const string SettingsPermission = "tenant:finance:invoice:settings";

    /// <summary>
    /// 查询发票设置详情。
    /// </summary>
    [HttpGet("settings/detail")]
    [PermissionAuthorize(ViewPermission, SettingsPermission)]
    [ProducesResponseType(typeof(ApiResponse<FinanceInvoiceSettingResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<FinanceInvoiceSettingResponse>> SettingsDetail(CancellationToken cancellationToken)
    {
        var result = await mediator.Send(new GetFinanceInvoiceSettingDetailQuery(), cancellationToken);
        return ApiResponse<FinanceInvoiceSettingResponse>.Ok(MapSetting(result));
    }

    /// <summary>
    /// 保存发票设置。
    /// </summary>
    [HttpPost("settings/save")]
    [PermissionAuthorize(SettingsPermission)]
    [ProducesResponseType(typeof(ApiResponse<FinanceInvoiceSettingResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<FinanceInvoiceSettingResponse>> SettingsSave(
        [FromBody] FinanceInvoiceSettingSaveRequest request,
        CancellationToken cancellationToken)
    {
        var result = await mediator.Send(new SaveFinanceInvoiceSettingCommand
        {
            CompanyName = request.CompanyName,
            TaxpayerNumber = request.TaxpayerNumber,
            RegisteredAddress = request.RegisteredAddress,
            RegisteredPhone = request.RegisteredPhone,
            BankName = request.BankName,
            BankAccount = request.BankAccount,
            EnableElectronicNormalInvoice = request.EnableElectronicNormalInvoice,
            EnableElectronicSpecialInvoice = request.EnableElectronicSpecialInvoice,
            EnableAutoIssue = request.EnableAutoIssue,
            AutoIssueMaxAmount = request.AutoIssueMaxAmount
        }, cancellationToken);

        return ApiResponse<FinanceInvoiceSettingResponse>.Ok(MapSetting(result));
    }

    /// <summary>
    /// 查询发票记录分页。
    /// </summary>
    [HttpGet("record/list")]
    [PermissionAuthorize(ViewPermission, IssuePermission, VoidPermission)]
    [ProducesResponseType(typeof(ApiResponse<FinanceInvoiceRecordListResultResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<FinanceInvoiceRecordListResultResponse>> RecordList(
        [FromQuery] FinanceInvoiceRecordListRequest request,
        CancellationToken cancellationToken)
    {
        var result = await mediator.Send(new GetFinanceInvoiceRecordListQuery
        {
            StartDateUtc = ParseDateOrNull(request.StartDate, nameof(request.StartDate)),
            EndDateUtc = ParseDateOrNull(request.EndDate, nameof(request.EndDate)),
            Status = ParseStatusOrNull(request.Status),
            InvoiceType = ParseInvoiceTypeOrNull(request.InvoiceType),
            Keyword = request.Keyword,
            Page = request.Page,
            PageSize = request.PageSize
        }, cancellationToken);

        return ApiResponse<FinanceInvoiceRecordListResultResponse>.Ok(new FinanceInvoiceRecordListResultResponse
        {
            Items = result.Items.Select(MapRecord).ToList(),
            Page = result.Page,
            PageSize = result.PageSize,
            TotalCount = result.TotalCount,
            Stats = new FinanceInvoiceStatsResponse
            {
                CurrentMonthIssuedAmount = result.Stats.CurrentMonthIssuedAmount,
                CurrentMonthIssuedCount = result.Stats.CurrentMonthIssuedCount,
                PendingCount = result.Stats.PendingCount,
                VoidedCount = result.Stats.VoidedCount
            }
        });
    }

    /// <summary>
    /// 查询发票记录详情。
    /// </summary>
    [HttpGet("record/detail")]
    [PermissionAuthorize(ViewPermission, IssuePermission, VoidPermission)]
    [ProducesResponseType(typeof(ApiResponse<FinanceInvoiceRecordDetailResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<FinanceInvoiceRecordDetailResponse>> RecordDetail(
        [FromQuery] FinanceInvoiceRecordDetailRequest request,
        CancellationToken cancellationToken)
    {
        var result = await mediator.Send(new GetFinanceInvoiceRecordDetailQuery
        {
            RecordId = StoreApiHelpers.ParseRequiredSnowflake(request.RecordId, nameof(request.RecordId))
        }, cancellationToken);

        return ApiResponse<FinanceInvoiceRecordDetailResponse>.Ok(MapRecordDetail(result));
    }

    /// <summary>
    /// 发票开票。
    /// </summary>
    [HttpPost("record/issue")]
    [PermissionAuthorize(IssuePermission)]
    [ProducesResponseType(typeof(ApiResponse<FinanceInvoiceIssueResultResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<FinanceInvoiceIssueResultResponse>> RecordIssue(
        [FromBody] FinanceInvoiceRecordIssueRequest request,
        CancellationToken cancellationToken)
    {
        var result = await mediator.Send(new IssueFinanceInvoiceRecordCommand
        {
            RecordId = StoreApiHelpers.ParseRequiredSnowflake(request.RecordId, nameof(request.RecordId)),
            ContactEmail = request.ContactEmail,
            IssueRemark = request.IssueRemark
        }, cancellationToken);

        return ApiResponse<FinanceInvoiceIssueResultResponse>.Ok(MapIssueResult(result));
    }

    /// <summary>
    /// 作废发票。
    /// </summary>
    [HttpPost("record/void")]
    [PermissionAuthorize(VoidPermission)]
    [ProducesResponseType(typeof(ApiResponse<FinanceInvoiceRecordDetailResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<FinanceInvoiceRecordDetailResponse>> RecordVoid(
        [FromBody] FinanceInvoiceRecordVoidRequest request,
        CancellationToken cancellationToken)
    {
        var result = await mediator.Send(new VoidFinanceInvoiceRecordCommand
        {
            RecordId = StoreApiHelpers.ParseRequiredSnowflake(request.RecordId, nameof(request.RecordId)),
            VoidReason = request.VoidReason
        }, cancellationToken);

        return ApiResponse<FinanceInvoiceRecordDetailResponse>.Ok(MapRecordDetail(result));
    }

    /// <summary>
    /// 申请发票。
    /// </summary>
    [HttpPost("record/apply")]
    [PermissionAuthorize(ViewPermission, IssuePermission)]
    [ProducesResponseType(typeof(ApiResponse<FinanceInvoiceRecordDetailResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<FinanceInvoiceRecordDetailResponse>> RecordApply(
        [FromBody] FinanceInvoiceRecordApplyRequest request,
        CancellationToken cancellationToken)
    {
        var result = await mediator.Send(new ApplyFinanceInvoiceRecordCommand
        {
            ApplicantName = request.ApplicantName,
            CompanyName = request.CompanyName,
            TaxpayerNumber = request.TaxpayerNumber,
            InvoiceType = request.InvoiceType,
            Amount = request.Amount,
            OrderNo = request.OrderNo,
            ContactEmail = request.ContactEmail,
            ContactPhone = request.ContactPhone,
            ApplyRemark = request.ApplyRemark,
            AppliedAt = request.AppliedAt
        }, cancellationToken);

        return ApiResponse<FinanceInvoiceRecordDetailResponse>.Ok(MapRecordDetail(result));
    }

    private static DateTime? ParseDateOrNull(string? value, string fieldName)
    {
        return string.IsNullOrWhiteSpace(value)
            ? null
            : StoreApiHelpers.ParseDateOnly(value, fieldName);
    }

    private static TenantInvoiceStatus? ParseStatusOrNull(string? value)
    {
        var normalized = (value ?? string.Empty).Trim().ToLowerInvariant();
        if (string.IsNullOrWhiteSpace(normalized))
        {
            return null;
        }

        return normalized switch
        {
            "pending" => TenantInvoiceStatus.Pending,
            "issued" => TenantInvoiceStatus.Issued,
            "voided" => TenantInvoiceStatus.Voided,
            _ => throw new BusinessException(ErrorCodes.BadRequest, "status 参数不合法")
        };
    }

    private static TenantInvoiceType? ParseInvoiceTypeOrNull(string? value)
    {
        var normalized = (value ?? string.Empty).Trim().ToLowerInvariant();
        if (string.IsNullOrWhiteSpace(normalized))
        {
            return null;
        }

        return normalized switch
        {
            "normal" => TenantInvoiceType.Normal,
            "special" => TenantInvoiceType.Special,
            _ => throw new BusinessException(ErrorCodes.BadRequest, "invoiceType 参数不合法")
        };
    }

    private static FinanceInvoiceSettingResponse MapSetting(FinanceInvoiceSettingDto source)
    {
        return new FinanceInvoiceSettingResponse
        {
            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 = source.AutoIssueMaxAmount
        };
    }

    private static FinanceInvoiceRecordResponse MapRecord(FinanceInvoiceRecordDto source)
    {
        return new FinanceInvoiceRecordResponse
        {
            RecordId = source.RecordId.ToString(),
            InvoiceNo = source.InvoiceNo,
            ApplicantName = source.ApplicantName,
            CompanyName = source.CompanyName,
            InvoiceType = source.InvoiceType,
            InvoiceTypeText = source.InvoiceTypeText,
            Amount = source.Amount,
            OrderNo = source.OrderNo,
            Status = source.Status,
            StatusText = source.StatusText,
            AppliedAt = source.AppliedAt.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)
        };
    }

    private static FinanceInvoiceRecordDetailResponse MapRecordDetail(FinanceInvoiceRecordDetailDto source)
    {
        return new FinanceInvoiceRecordDetailResponse
        {
            RecordId = source.RecordId.ToString(),
            InvoiceNo = source.InvoiceNo,
            ApplicantName = source.ApplicantName,
            CompanyName = source.CompanyName,
            TaxpayerNumber = source.TaxpayerNumber,
            InvoiceType = source.InvoiceType,
            InvoiceTypeText = source.InvoiceTypeText,
            Amount = source.Amount,
            OrderNo = source.OrderNo,
            ContactEmail = source.ContactEmail,
            ContactPhone = source.ContactPhone,
            ApplyRemark = source.ApplyRemark,
            Status = source.Status,
            StatusText = source.StatusText,
            AppliedAt = source.AppliedAt.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
            IssuedAt = source.IssuedAt?.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
            IssuedByUserId = source.IssuedByUserId?.ToString(),
            IssueRemark = source.IssueRemark,
            VoidedAt = source.VoidedAt?.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
            VoidedByUserId = source.VoidedByUserId?.ToString(),
            VoidReason = source.VoidReason
        };
    }

    private static FinanceInvoiceIssueResultResponse MapIssueResult(FinanceInvoiceIssueResultDto source)
    {
        return new FinanceInvoiceIssueResultResponse
        {
            RecordId = source.RecordId.ToString(),
            InvoiceNo = source.InvoiceNo,
            CompanyName = source.CompanyName,
            Amount = source.Amount,
            ContactEmail = source.ContactEmail,
            IssuedAt = source.IssuedAt.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
            Status = source.Status,
            StatusText = source.StatusText
        };
    }
}
