using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Net.Http.Headers;
using System.ComponentModel.DataAnnotations;
using TakeoutSaaS.Application.App.Billings.Commands;
using TakeoutSaaS.Application.App.Billings.Dto;
using TakeoutSaaS.Application.App.Billings.Queries;
using TakeoutSaaS.Module.Authorization.Attributes;
using TakeoutSaaS.Shared.Abstractions.Results;
using TakeoutSaaS.Shared.Web.Api;

namespace TakeoutSaaS.AdminApi.Controllers;

/// <summary>
/// 账单管理。
/// </summary>
[ApiVersion("1.0")]
[Authorize]
[Route("api/admin/v{version:apiVersion}/billings")]
public sealed class BillingsController(IMediator mediator) : BaseApiController
{
    /// <summary>
    /// 分页查询账单列表。
    /// </summary>
    /// <returns>账单分页结果。</returns>
    [HttpGet]
    [PermissionAuthorize("bill:read")]
    [ProducesResponseType(typeof(ApiResponse<PagedResult<BillingListDto>>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<PagedResult<BillingListDto>>> GetList([FromQuery] GetBillingListQuery query, CancellationToken cancellationToken)
    {
        // 1. 查询账单列表
        var result = await mediator.Send(query, cancellationToken);

        // 2. 返回分页结果
        return ApiResponse<PagedResult<BillingListDto>>.Ok(result);
    }

    /// <summary>
    /// 获取账单详情。
    /// </summary>
    /// <param name="id">账单 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>账单详情。</returns>
    [HttpGet("{id:long}")]
    [PermissionAuthorize("bill:read")]
    [ProducesResponseType(typeof(ApiResponse<BillingDetailDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    public async Task<ApiResponse<BillingDetailDto>> GetDetail(long id, CancellationToken cancellationToken)
    {
        // 1. 查询账单详情（若不存在则抛出业务异常，由全局异常处理转换为 404）
        var result = await mediator.Send(new GetBillingDetailQuery { BillingId = id }, cancellationToken);

        // 2. 返回详情
        return ApiResponse<BillingDetailDto>.Ok(result);
    }

    /// <summary>
    /// 手动创建账单。
    /// </summary>
    /// <param name="command">创建账单命令。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>创建的账单信息。</returns>
    [HttpPost]
    [PermissionAuthorize("bill:create")]
    [ProducesResponseType(typeof(ApiResponse<BillingDetailDto>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<BillingDetailDto>> Create([FromBody, Required] CreateBillingCommand command, CancellationToken cancellationToken)
    {
        // 1. 创建账单
        var result = await mediator.Send(command, cancellationToken);

        // 2. 返回创建结果
        return ApiResponse<BillingDetailDto>.Ok(result);
    }

    /// <summary>
    /// 更新账单状态。
    /// </summary>
    /// <param name="id">账单 ID。</param>
    /// <param name="command">更新状态命令。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>更新结果。</returns>
    [HttpPut("{id:long}/status")]
    [PermissionAuthorize("bill:update")]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    public async Task<ApiResponse<object>> UpdateStatus(long id, [FromBody, Required] UpdateBillingStatusCommand command, CancellationToken cancellationToken)
    {
        // 1. 绑定账单标识
        command = command with { BillingId = id };

        // 2. 更新账单状态（若不存在则抛出业务异常，由全局异常处理转换为 404）
        await mediator.Send(command, cancellationToken);

        // 3. 返回成功结果
        return ApiResponse<object>.Ok(null);
    }

    /// <summary>
    /// 取消账单。
    /// </summary>
    /// <param name="id">账单 ID。</param>
    /// <param name="reason">取消原因（可选）。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>取消结果。</returns>
    [HttpDelete("{id:long}")]
    [PermissionAuthorize("bill:delete")]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    public async Task<ApiResponse<object>> Cancel(long id, [FromQuery] string? reason, CancellationToken cancellationToken)
    {
        // 1. 取消账单（取消原因支持可选）
        await mediator.Send(new CancelBillingCommand { BillingId = id, Reason = reason ?? string.Empty }, cancellationToken);

        // 2. 返回成功结果
        return ApiResponse<object>.Ok(null);
    }

    /// <summary>
    /// 获取账单支付记录。
    /// </summary>
    /// <param name="id">账单 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>支付记录列表。</returns>
    [HttpGet("{id:long}/payments")]
    [PermissionAuthorize("bill:read")]
    [ProducesResponseType(typeof(ApiResponse<List<PaymentRecordDto>>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<List<PaymentRecordDto>>> GetPayments(long id, CancellationToken cancellationToken)
    {
        // 1. 查询支付记录
        var result = await mediator.Send(new GetBillingPaymentsQuery { BillingId = id }, cancellationToken);

        // 2. 返回列表
        return ApiResponse<List<PaymentRecordDto>>.Ok(result);
    }

    /// <summary>
    /// 记录支付（线下支付确认）。
    /// </summary>
    /// <param name="id">账单 ID。</param>
    /// <param name="command">记录支付命令。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>支付记录信息。</returns>
    [HttpPost("{id:long}/payments")]
    [PermissionAuthorize("bill:pay")]
    [ProducesResponseType(typeof(ApiResponse<PaymentRecordDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    public async Task<ApiResponse<PaymentRecordDto>> RecordPayment(long id, [FromBody, Required] RecordPaymentCommand command, CancellationToken cancellationToken)
    {
        // 1. 绑定账单标识
        command = command with { BillingId = id };

        // 2. 记录支付
        var result = await mediator.Send(command, cancellationToken);

        // 3. 返回支付记录
        return ApiResponse<PaymentRecordDto>.Ok(result);
    }

    /// <summary>
    /// 一键确认收款（记录支付 + 立即审核通过）。
    /// </summary>
    /// <param name="id">账单 ID。</param>
    /// <param name="command">确认收款命令。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>确认后的支付记录。</returns>
    [HttpPost("{id:long}/payments/confirm")]
    [PermissionAuthorize("bill:pay")]
    [ProducesResponseType(typeof(ApiResponse<PaymentRecordDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    public async Task<ApiResponse<PaymentRecordDto>> ConfirmPayment(long id, [FromBody, Required] ConfirmPaymentCommand command, CancellationToken cancellationToken)
    {
        // 1. 绑定账单标识
        command = command with { BillingId = id };

        // 2. (空行后) 一键确认收款（含：写入 VerifiedBy/VerifiedAt，并同步更新账单已收金额/状态）
        var result = await mediator.Send(command, cancellationToken);

        // 3. (空行后) 返回结果
        return ApiResponse<PaymentRecordDto>.Ok(result);
    }

    /// <summary>
    /// 审核支付记录。
    /// </summary>
    /// <param name="paymentId">支付记录 ID。</param>
    /// <param name="command">审核参数。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>审核后的支付记录。</returns>
    [HttpPut("payments/{paymentId:long}/verify")]
    [PermissionAuthorize("bill:update")]
    [ProducesResponseType(typeof(ApiResponse<PaymentRecordDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    public async Task<ApiResponse<PaymentRecordDto>> VerifyPayment(long paymentId, [FromBody, Required] VerifyPaymentCommand command, CancellationToken cancellationToken)
    {
        // 1. 绑定支付记录标识
        command = command with { PaymentId = paymentId };

        // 2. (空行后) 审核支付记录
        var result = await mediator.Send(command, cancellationToken);

        // 3. (空行后) 返回审核结果
        return ApiResponse<PaymentRecordDto>.Ok(result);
    }

    /// <summary>
    /// 批量更新账单状态。
    /// </summary>
    /// <param name="command">批量更新命令。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>更新条数。</returns>
    [HttpPost("batch/status")]
    [PermissionAuthorize("bill:update")]
    [ProducesResponseType(typeof(ApiResponse<int>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<int>> BatchUpdateStatus([FromBody, Required] BatchUpdateStatusCommand command, CancellationToken cancellationToken)
    {
        // 1. 执行批量更新
        var affected = await mediator.Send(command, cancellationToken);

        // 2. 返回更新条数
        return ApiResponse<int>.Ok(affected);
    }

    /// <summary>
    /// 导出账单（Excel/PDF/CSV）。
    /// </summary>
    /// <param name="query">导出请求。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>导出文件。</returns>
    [HttpPost("export")]
    [PermissionAuthorize("bill:read")]
    [Produces("application/octet-stream")]
    [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
    public async Task<IActionResult> Export([FromBody, Required] ExportBillingsQuery query, CancellationToken cancellationToken)
    {
        // 1. 执行导出
        var bytes = await mediator.Send(query, cancellationToken);

        // 2. (空行后) 解析格式并生成文件名
        var extension = ResolveExportFileExtension(query.Format);
        var fileName = $"billings_{DateTime.UtcNow:yyyyMMdd_HHmmss}.{extension}";

        // 3. (空行后) 显式写入 Content-Disposition，确保浏览器以附件形式下载
        Response.Headers[HeaderNames.ContentDisposition] = new ContentDispositionHeaderValue("attachment")
        {
            FileName = fileName,
            FileNameStar = fileName
        }.ToString();

        // 4. (空行后) 返回二进制流（统一 octet-stream，避免被默认 JSON Produces 影响）
        return File(bytes, "application/octet-stream");
    }

    /// <summary>
    /// 获取账单统计数据。
    /// </summary>
    /// <param name="query">统计查询参数。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>统计结果。</returns>
    [HttpGet("statistics")]
    [PermissionAuthorize("bill:read")]
    [ProducesResponseType(typeof(ApiResponse<BillingStatisticsDto>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<BillingStatisticsDto>> Statistics([FromQuery] GetBillingStatisticsQuery query, CancellationToken cancellationToken)
    {
        // 1. 查询统计数据
        var result = await mediator.Send(query, cancellationToken);

        // 2. 返回统计结果
        return ApiResponse<BillingStatisticsDto>.Ok(result);
    }

    /// <summary>
    /// 获取逾期账单列表。
    /// </summary>
    /// <param name="query">逾期列表查询参数。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>逾期账单分页结果。</returns>
    [HttpGet("overdue")]
    [PermissionAuthorize("bill:read")]
    [ProducesResponseType(typeof(ApiResponse<PagedResult<BillingListDto>>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<PagedResult<BillingListDto>>> Overdue([FromQuery] GetOverdueBillingsQuery query, CancellationToken cancellationToken)
    {
        // 1. 查询逾期账单分页列表
        var result = await mediator.Send(query, cancellationToken);

        // 2. 返回分页结果
        return ApiResponse<PagedResult<BillingListDto>>.Ok(result);
    }

    private static string ResolveExportFileExtension(string? format)
    {
        // 1. 归一化导出格式
        var normalized = (format ?? string.Empty).Trim();

        // 2. (空行后) 映射扩展名
        return normalized.ToUpperInvariant() switch
        {
            "PDF" => "pdf",
            "CSV" => "csv",
            _ => "xlsx"
        };
    }
}
