using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using TakeoutSaaS.Application.App.Finance.Reports.Dto;
using TakeoutSaaS.Application.App.Finance.Reports.Queries;
using TakeoutSaaS.Application.App.Stores.Services;
using TakeoutSaaS.Domain.Finance.Enums;
using TakeoutSaaS.Infrastructure.App.Persistence;
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/report")]
public sealed class FinanceReportController(
    IMediator mediator,
    TakeoutAppDbContext dbContext,
    StoreContextService storeContextService) : BaseApiController
{
    private const string ViewPermission = "tenant:statistics:report:view";
    private const string ExportPermission = "tenant:statistics:report:export";

    /// <summary>
    /// 查询经营报表列表。
    /// </summary>
    [HttpGet("list")]
    [PermissionAuthorize(ViewPermission)]
    [ProducesResponseType(typeof(ApiResponse<FinanceBusinessReportListResultResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<FinanceBusinessReportListResultResponse>> List(
        [FromQuery] FinanceBusinessReportListRequest request,
        CancellationToken cancellationToken)
    {
        // 1. 校验门店访问权限并解析查询参数。
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);
        var periodType = ParsePeriodType(request.PeriodType);

        // 2. 发起查询并返回结果。
        var result = await mediator.Send(new SearchFinanceBusinessReportListQuery
        {
            StoreId = storeId,
            PeriodType = periodType,
            Page = Math.Max(1, request.Page),
            PageSize = Math.Clamp(request.PageSize, 1, 200)
        }, cancellationToken);

        return ApiResponse<FinanceBusinessReportListResultResponse>.Ok(new FinanceBusinessReportListResultResponse
        {
            Items = result.Items.Select(MapListItem).ToList(),
            Total = result.Total,
            Page = result.Page,
            PageSize = result.PageSize
        });
    }

    /// <summary>
    /// 查询经营报表详情。
    /// </summary>
    [HttpGet("detail")]
    [PermissionAuthorize(ViewPermission)]
    [ProducesResponseType(typeof(ApiResponse<FinanceBusinessReportDetailResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<FinanceBusinessReportDetailResponse>> Detail(
        [FromQuery] FinanceBusinessReportDetailRequest request,
        CancellationToken cancellationToken)
    {
        // 1. 校验门店访问权限并解析参数。
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);
        var reportId = StoreApiHelpers.ParseRequiredSnowflake(request.ReportId, nameof(request.ReportId));

        // 2. 发起详情查询。
        var detail = await mediator.Send(new GetFinanceBusinessReportDetailQuery
        {
            StoreId = storeId,
            ReportId = reportId
        }, cancellationToken);

        if (detail is null)
        {
            return ApiResponse<FinanceBusinessReportDetailResponse>.Error(ErrorCodes.NotFound, "经营报表不存在");
        }

        return ApiResponse<FinanceBusinessReportDetailResponse>.Ok(MapDetail(detail));
    }

    /// <summary>
    /// 导出单条报表 PDF。
    /// </summary>
    [HttpGet("export/pdf")]
    [PermissionAuthorize(ExportPermission)]
    [ProducesResponseType(typeof(ApiResponse<FinanceBusinessReportExportResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<FinanceBusinessReportExportResponse>> ExportPdf(
        [FromQuery] FinanceBusinessReportDetailRequest request,
        CancellationToken cancellationToken)
    {
        // 1. 校验门店访问权限并解析参数。
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);
        var reportId = StoreApiHelpers.ParseRequiredSnowflake(request.ReportId, nameof(request.ReportId));

        // 2. 执行导出。
        var export = await mediator.Send(new ExportFinanceBusinessReportPdfQuery
        {
            StoreId = storeId,
            ReportId = reportId
        }, cancellationToken);

        return ApiResponse<FinanceBusinessReportExportResponse>.Ok(MapExport(export));
    }

    /// <summary>
    /// 导出单条报表 Excel。
    /// </summary>
    [HttpGet("export/excel")]
    [PermissionAuthorize(ExportPermission)]
    [ProducesResponseType(typeof(ApiResponse<FinanceBusinessReportExportResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<FinanceBusinessReportExportResponse>> ExportExcel(
        [FromQuery] FinanceBusinessReportDetailRequest request,
        CancellationToken cancellationToken)
    {
        // 1. 校验门店访问权限并解析参数。
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);
        var reportId = StoreApiHelpers.ParseRequiredSnowflake(request.ReportId, nameof(request.ReportId));

        // 2. 执行导出。
        var export = await mediator.Send(new ExportFinanceBusinessReportExcelQuery
        {
            StoreId = storeId,
            ReportId = reportId
        }, cancellationToken);

        return ApiResponse<FinanceBusinessReportExportResponse>.Ok(MapExport(export));
    }

    /// <summary>
    /// 批量导出报表 ZIP（PDF + Excel）。
    /// </summary>
    [HttpGet("export/batch")]
    [PermissionAuthorize(ExportPermission)]
    [ProducesResponseType(typeof(ApiResponse<FinanceBusinessReportExportResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<FinanceBusinessReportExportResponse>> ExportBatch(
        [FromQuery] FinanceBusinessReportBatchExportRequest request,
        CancellationToken cancellationToken)
    {
        // 1. 校验门店访问权限并解析参数。
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);
        var periodType = ParsePeriodType(request.PeriodType);

        // 2. 执行批量导出。
        var export = await mediator.Send(new ExportFinanceBusinessReportBatchQuery
        {
            StoreId = storeId,
            PeriodType = periodType,
            Page = Math.Max(1, request.Page),
            PageSize = Math.Clamp(request.PageSize, 1, 200)
        }, cancellationToken);

        return ApiResponse<FinanceBusinessReportExportResponse>.Ok(MapExport(export));
    }

    private async Task EnsureStoreAccessibleAsync(long storeId, CancellationToken cancellationToken)
    {
        var (tenantId, merchantId) = StoreApiHelpers.GetTenantMerchantContext(storeContextService);
        await StoreApiHelpers.EnsureStoreAccessibleAsync(dbContext, tenantId, merchantId, storeId, cancellationToken);
    }

    private static FinanceBusinessReportPeriodType ParsePeriodType(string? value)
    {
        return (value ?? string.Empty).Trim().ToLowerInvariant() switch
        {
            "" or "daily" => FinanceBusinessReportPeriodType.Daily,
            "weekly" => FinanceBusinessReportPeriodType.Weekly,
            "monthly" => FinanceBusinessReportPeriodType.Monthly,
            _ => throw new BusinessException(ErrorCodes.BadRequest, "periodType 参数不合法")
        };
    }

    private static FinanceBusinessReportListItemResponse MapListItem(FinanceBusinessReportListItemDto source)
    {
        return new FinanceBusinessReportListItemResponse
        {
            ReportId = source.ReportId,
            DateText = source.DateText,
            RevenueAmount = source.RevenueAmount,
            OrderCount = source.OrderCount,
            AverageOrderValue = source.AverageOrderValue,
            RefundRatePercent = source.RefundRatePercent,
            CostTotalAmount = source.CostTotalAmount,
            NetProfitAmount = source.NetProfitAmount,
            ProfitRatePercent = source.ProfitRatePercent,
            Status = source.Status,
            StatusText = source.StatusText,
            CanDownload = source.CanDownload
        };
    }

    private static FinanceBusinessReportDetailResponse MapDetail(FinanceBusinessReportDetailDto source)
    {
        return new FinanceBusinessReportDetailResponse
        {
            ReportId = source.ReportId,
            Title = source.Title,
            PeriodType = source.PeriodType,
            Status = source.Status,
            StatusText = source.StatusText,
            Kpis = source.Kpis.Select(item => new FinanceBusinessReportKpiResponse
            {
                Key = item.Key,
                Label = item.Label,
                ValueText = item.ValueText,
                YoyChangeRate = item.YoyChangeRate,
                MomChangeRate = item.MomChangeRate
            }).ToList(),
            IncomeBreakdowns = source.IncomeBreakdowns.Select(MapBreakdown).ToList(),
            CostBreakdowns = source.CostBreakdowns.Select(MapBreakdown).ToList()
        };
    }

    private static FinanceBusinessReportBreakdownItemResponse MapBreakdown(FinanceBusinessReportBreakdownItemDto source)
    {
        return new FinanceBusinessReportBreakdownItemResponse
        {
            Key = source.Key,
            Label = source.Label,
            Amount = source.Amount,
            RatioPercent = source.RatioPercent
        };
    }

    private static FinanceBusinessReportExportResponse MapExport(FinanceBusinessReportExportDto source)
    {
        return new FinanceBusinessReportExportResponse
        {
            FileName = source.FileName,
            FileContentBase64 = source.FileContentBase64,
            TotalCount = source.TotalCount
        };
    }
}
