using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using TakeoutSaaS.Application.App.Coupons.Calendar.Dto;
using TakeoutSaaS.Application.App.Coupons.Calendar.Queries;
using TakeoutSaaS.Application.App.Stores.Services;
using TakeoutSaaS.Infrastructure.App.Persistence;
using TakeoutSaaS.Module.Authorization.Attributes;
using TakeoutSaaS.Shared.Abstractions.Results;
using TakeoutSaaS.Shared.Web.Api;
using TakeoutSaaS.TenantApi.Contracts.Marketing;

namespace TakeoutSaaS.TenantApi.Controllers;

/// <summary>
/// 营销中心营销日历。
/// </summary>
[ApiVersion("1.0")]
[Authorize]
[Route("api/tenant/v{version:apiVersion}/marketing/calendar")]
public sealed class MarketingCalendarController(
    IMediator mediator,
    TakeoutAppDbContext dbContext,
    StoreContextService storeContextService)
    : BaseApiController
{
    private const string ViewPermission = "tenant:marketing:calendar:view";
    private const string ManagePermission = "tenant:marketing:calendar:manage";

    /// <summary>
    /// 获取营销日历总览。
    /// </summary>
    [HttpGet("overview")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MarketingCalendarOverviewResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MarketingCalendarOverviewResponse>> Overview(
        [FromQuery] MarketingCalendarOverviewRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new GetMarketingCalendarOverviewQuery
        {
            StoreId = storeId,
            Year = request.Year,
            Month = request.Month
        }, cancellationToken);

        return ApiResponse<MarketingCalendarOverviewResponse>.Ok(MapOverview(result));
    }

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

    private static MarketingCalendarOverviewResponse MapOverview(MarketingCalendarOverviewDto source)
    {
        return new MarketingCalendarOverviewResponse
        {
            Month = source.Month,
            Year = source.Year,
            MonthValue = source.MonthValue,
            MonthStartDate = StoreApiHelpers.ToDateOnly(source.MonthStartDate),
            MonthEndDate = StoreApiHelpers.ToDateOnly(source.MonthEndDate),
            TodayDay = source.TodayDay,
            Days = source.Days
                .Select(item => new MarketingCalendarDayResponse
                {
                    Day = item.Day,
                    IsWeekend = item.IsWeekend,
                    IsToday = item.IsToday
                })
                .ToList(),
            Legends = source.Legends
                .Select(item => new MarketingCalendarLegendResponse
                {
                    Type = item.Type,
                    Label = item.Label,
                    Color = item.Color
                })
                .ToList(),
            Stats = new MarketingCalendarStatsResponse
            {
                TotalActivityCount = source.Stats.TotalActivityCount,
                OngoingCount = source.Stats.OngoingCount,
                MaxConcurrentCount = source.Stats.MaxConcurrentCount,
                EstimatedDiscountAmount = source.Stats.EstimatedDiscountAmount
            },
            ConflictBanner = source.ConflictBanner is null
                ? null
                : new MarketingCalendarConflictBannerResponse
                {
                    ConflictId = source.ConflictBanner.ConflictId,
                    StartDay = source.ConflictBanner.StartDay,
                    EndDay = source.ConflictBanner.EndDay,
                    ActivityCount = source.ConflictBanner.ActivityCount,
                    MaxConcurrentCount = source.ConflictBanner.MaxConcurrentCount,
                    ConflictCount = source.ConflictBanner.ConflictCount
                },
            Conflicts = source.Conflicts
                .Select(MapConflict)
                .ToList(),
            Activities = source.Activities
                .Select(MapActivity)
                .ToList()
        };
    }

    private static MarketingCalendarActivityResponse MapActivity(MarketingCalendarActivityDto source)
    {
        return new MarketingCalendarActivityResponse
        {
            ActivityId = source.ActivityId,
            SourceType = source.SourceType,
            SourceId = source.SourceId,
            CalendarType = source.CalendarType,
            Name = source.Name,
            Color = source.Color,
            Summary = source.Summary,
            DisplayStatus = source.DisplayStatus,
            IsDimmed = source.IsDimmed,
            StartDate = StoreApiHelpers.ToDateOnly(source.StartDate),
            EndDate = StoreApiHelpers.ToDateOnly(source.EndDate),
            EstimatedDiscountAmount = source.EstimatedDiscountAmount,
            Bars = source.Bars.Select(item => new MarketingCalendarActivityBarResponse
            {
                BarId = item.BarId,
                StartDay = item.StartDay,
                EndDay = item.EndDay,
                Label = item.Label,
                IsMilestone = item.IsMilestone,
                IsDimmed = item.IsDimmed
            }).ToList(),
            Detail = new MarketingCalendarActivityDetailResponse
            {
                ModuleName = source.Detail.ModuleName,
                Description = source.Detail.Description,
                Fields = source.Detail.Fields.Select(item => new MarketingCalendarDetailFieldResponse
                {
                    Label = item.Label,
                    Value = item.Value
                }).ToList()
            }
        };
    }

    private static MarketingCalendarConflictResponse MapConflict(MarketingCalendarConflictDto source)
    {
        return new MarketingCalendarConflictResponse
        {
            ConflictId = source.ConflictId,
            StartDay = source.StartDay,
            EndDay = source.EndDay,
            ActivityCount = source.ActivityCount,
            MaxConcurrentCount = source.MaxConcurrentCount,
            ActivityIds = source.ActivityIds.ToList(),
            Activities = source.Activities.Select(item => new MarketingCalendarConflictActivityResponse
            {
                ActivityId = item.ActivityId,
                CalendarType = item.CalendarType,
                Name = item.Name,
                Summary = item.Summary,
                Color = item.Color,
                DisplayStatus = item.DisplayStatus
            }).ToList()
        };
    }
}
