using System.Globalization;
using Asp.Versioning;
using Hangfire;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using TakeoutSaaS.Application.App.Members.MessageReach.Dto;
using TakeoutSaaS.Application.App.Members.MessageReach.Services;
using TakeoutSaaS.Application.App.Stores.Services;
using TakeoutSaaS.Infrastructure.App.Persistence;
using TakeoutSaaS.Module.Authorization.Attributes;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Results;
using TakeoutSaaS.Shared.Web.Api;
using TakeoutSaaS.TenantApi.Contracts.Member;
using TakeoutSaaS.TenantApi.Services;

namespace TakeoutSaaS.TenantApi.Controllers;

/// <summary>
/// 会员消息触达管理。
/// </summary>
[ApiVersion("1.0")]
[Authorize]
[Route("api/tenant/v{version:apiVersion}/member/message-reach")]
public sealed class MemberMessageReachController(
    IMemberMessageReachAppService memberMessageReachAppService,
    TakeoutAppDbContext dbContext,
    StoreContextService storeContextService)
    : BaseApiController
{
    private const string ViewPermission = "tenant:member:message-reach:view";
    private const string ManagePermission = "tenant:member:message-reach:manage";

    /// <summary>
    /// 获取页面统计。
    /// </summary>
    [HttpGet("stats")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberMessageReachStatsResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberMessageReachStatsResponse>> Stats(
        [FromQuery] MemberMessageReachStatsRequest request,
        CancellationToken cancellationToken)
    {
        var tenantId = await ResolveTenantIdAsync(request.StoreId, cancellationToken);
        var result = await memberMessageReachAppService.GetStatsAsync(tenantId, cancellationToken);
        return ApiResponse<MemberMessageReachStatsResponse>.Ok(new MemberMessageReachStatsResponse
        {
            MonthlySentCount = result.MonthlySentCount,
            ReachMemberCount = result.ReachMemberCount,
            OpenRate = result.OpenRate,
            ConversionRate = result.ConversionRate
        });
    }

    /// <summary>
    /// 分页查询消息列表。
    /// </summary>
    [HttpGet("list")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberMessageReachListResultResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberMessageReachListResultResponse>> List(
        [FromQuery] MemberMessageReachListRequest request,
        CancellationToken cancellationToken)
    {
        var tenantId = ResolveTenantId();
        var result = await memberMessageReachAppService.SearchMessagesAsync(
            tenantId,
            new SearchMemberMessageInput
            {
                Status = request.Status,
                Channel = request.Channel,
                Keyword = request.Keyword,
                Page = request.Page,
                PageSize = request.PageSize
            },
            cancellationToken);

        return ApiResponse<MemberMessageReachListResultResponse>.Ok(new MemberMessageReachListResultResponse
        {
            Items = result.Items.Select(MapMessageListItem).ToList(),
            Page = result.Page,
            PageSize = result.PageSize,
            TotalCount = result.TotalCount
        });
    }

    /// <summary>
    /// 获取消息详情。
    /// </summary>
    [HttpGet("detail")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberMessageReachDetailResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberMessageReachDetailResponse>> Detail(
        [FromQuery] MemberMessageReachDetailRequest request,
        CancellationToken cancellationToken)
    {
        var tenantId = ResolveTenantId();
        var messageId = StoreApiHelpers.ParseRequiredSnowflake(request.MessageId, nameof(request.MessageId));
        var result = await memberMessageReachAppService.GetMessageDetailAsync(tenantId, messageId, cancellationToken);
        if (result is null)
        {
            return ApiResponse<MemberMessageReachDetailResponse>.Error(ErrorCodes.NotFound, "消息不存在");
        }

        return ApiResponse<MemberMessageReachDetailResponse>.Ok(MapMessageDetail(result));
    }

    /// <summary>
    /// 保存消息（草稿/发送）。
    /// </summary>
    [HttpPost("save")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberMessageDispatchMetaResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberMessageDispatchMetaResponse>> Save(
        [FromBody] SaveMemberMessageReachRequest request,
        CancellationToken cancellationToken)
    {
        var tenantId = await ResolveTenantIdAsync(request.StoreId, cancellationToken);
        var messageId = StoreApiHelpers.ParseSnowflakeOrNull(request.MessageId);
        var previousMeta = messageId.HasValue
            ? await memberMessageReachAppService.GetDispatchMetaAsync(tenantId, messageId.Value, cancellationToken)
            : null;

        var saved = await memberMessageReachAppService.SaveMessageAsync(
            tenantId,
            new SaveMemberMessageInput
            {
                MessageId = messageId,
                StoreId = StoreApiHelpers.ParseSnowflakeOrNull(request.StoreId),
                TemplateId = StoreApiHelpers.ParseSnowflakeOrNull(request.TemplateId),
                Title = request.Title,
                Content = request.Content,
                Channels = request.Channels,
                AudienceType = request.AudienceType,
                AudienceTags = request.AudienceTags,
                ScheduleType = request.ScheduleType,
                ScheduledAt = request.ScheduledAt,
                SubmitAction = request.SubmitAction
            },
            cancellationToken);

        // 1. 清理旧任务（若存在）。
        if (!string.IsNullOrWhiteSpace(previousMeta?.HangfireJobId))
        {
            BackgroundJob.Delete(previousMeta.HangfireJobId);
        }

        // 2. 发送动作创建新任务并回写任务 ID。
        if (string.Equals(request.SubmitAction, "send", StringComparison.OrdinalIgnoreCase))
        {
            var newJobId = ScheduleDispatchJob(saved.MessageId, saved.ScheduleType, saved.ScheduledAt);
            await memberMessageReachAppService.BindDispatchJobAsync(tenantId, saved.MessageId, newJobId, cancellationToken);
        }

        // 3. 返回最新调度状态。
        var latest = await memberMessageReachAppService.GetDispatchMetaAsync(tenantId, saved.MessageId, cancellationToken);
        return ApiResponse<MemberMessageDispatchMetaResponse>.Ok(MapDispatchMeta(latest ?? saved));
    }

    /// <summary>
    /// 删除消息。
    /// </summary>
    [HttpPost("delete")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<object>> Delete(
        [FromBody] DeleteMemberMessageReachRequest request,
        CancellationToken cancellationToken)
    {
        var tenantId = ResolveTenantId();
        var messageId = StoreApiHelpers.ParseRequiredSnowflake(request.MessageId, nameof(request.MessageId));
        var oldJobId = await memberMessageReachAppService.DeleteMessageAsync(tenantId, messageId, cancellationToken);
        if (!string.IsNullOrWhiteSpace(oldJobId))
        {
            BackgroundJob.Delete(oldJobId);
        }

        return ApiResponse<object>.Ok(null);
    }

    /// <summary>
    /// 估算目标人群。
    /// </summary>
    [HttpPost("audience/estimate")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberMessageAudienceEstimateResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberMessageAudienceEstimateResponse>> EstimateAudience(
        [FromBody] MemberMessageAudienceEstimateRequest request,
        CancellationToken cancellationToken)
    {
        var tenantId = ResolveTenantId();
        var result = await memberMessageReachAppService.EstimateAudienceAsync(
            tenantId,
            new MemberMessageAudienceEstimateInput
            {
                AudienceType = request.AudienceType,
                Tags = request.Tags
            },
            cancellationToken);

        return ApiResponse<MemberMessageAudienceEstimateResponse>.Ok(new MemberMessageAudienceEstimateResponse
        {
            ReachCount = result.ReachCount
        });
    }

    /// <summary>
    /// 分页查询模板。
    /// </summary>
    [HttpGet("template/list")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberMessageTemplateListResultResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberMessageTemplateListResultResponse>> TemplateList(
        [FromQuery] MemberMessageTemplateListRequest request,
        CancellationToken cancellationToken)
    {
        var tenantId = ResolveTenantId();
        var result = await memberMessageReachAppService.SearchTemplatesAsync(
            tenantId,
            new SearchMemberMessageTemplateInput
            {
                Category = request.Category,
                Keyword = request.Keyword,
                Page = request.Page,
                PageSize = request.PageSize
            },
            cancellationToken);

        return ApiResponse<MemberMessageTemplateListResultResponse>.Ok(new MemberMessageTemplateListResultResponse
        {
            Items = result.Items.Select(MapTemplate).ToList(),
            Page = result.Page,
            PageSize = result.PageSize,
            TotalCount = result.TotalCount
        });
    }

    /// <summary>
    /// 获取模板详情。
    /// </summary>
    [HttpGet("template/detail")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberMessageTemplateResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberMessageTemplateResponse>> TemplateDetail(
        [FromQuery] MemberMessageTemplateDetailRequest request,
        CancellationToken cancellationToken)
    {
        var tenantId = ResolveTenantId();
        var templateId = StoreApiHelpers.ParseRequiredSnowflake(request.TemplateId, nameof(request.TemplateId));
        var result = await memberMessageReachAppService.GetTemplateAsync(tenantId, templateId, cancellationToken);
        if (result is null)
        {
            return ApiResponse<MemberMessageTemplateResponse>.Error(ErrorCodes.NotFound, "模板不存在");
        }

        return ApiResponse<MemberMessageTemplateResponse>.Ok(MapTemplate(result));
    }

    /// <summary>
    /// 保存模板。
    /// </summary>
    [HttpPost("template/save")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberMessageTemplateResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberMessageTemplateResponse>> SaveTemplate(
        [FromBody] SaveMemberMessageTemplateRequest request,
        CancellationToken cancellationToken)
    {
        var tenantId = ResolveTenantId();
        var result = await memberMessageReachAppService.SaveTemplateAsync(
            tenantId,
            new SaveMemberMessageTemplateInput
            {
                TemplateId = StoreApiHelpers.ParseSnowflakeOrNull(request.TemplateId),
                Name = request.Name,
                Category = request.Category,
                Content = request.Content
            },
            cancellationToken);

        return ApiResponse<MemberMessageTemplateResponse>.Ok(MapTemplate(result));
    }

    /// <summary>
    /// 删除模板。
    /// </summary>
    [HttpPost("template/delete")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<object>> DeleteTemplate(
        [FromBody] DeleteMemberMessageTemplateRequest request,
        CancellationToken cancellationToken)
    {
        var tenantId = ResolveTenantId();
        var templateId = StoreApiHelpers.ParseRequiredSnowflake(request.TemplateId, nameof(request.TemplateId));
        await memberMessageReachAppService.DeleteTemplateAsync(tenantId, templateId, cancellationToken);
        return ApiResponse<object>.Ok(null);
    }

    private long ResolveTenantId()
    {
        var (tenantId, _) = StoreApiHelpers.GetTenantMerchantContext(storeContextService);
        return tenantId;
    }

    private async Task<long> ResolveTenantIdAsync(string? storeId, CancellationToken cancellationToken)
    {
        var (tenantId, merchantId) = StoreApiHelpers.GetTenantMerchantContext(storeContextService);
        if (string.IsNullOrWhiteSpace(storeId))
        {
            return tenantId;
        }

        var parsedStoreId = StoreApiHelpers.ParseRequiredSnowflake(storeId, nameof(storeId));
        await StoreApiHelpers.EnsureStoreAccessibleAsync(
            dbContext,
            tenantId,
            merchantId,
            parsedStoreId,
            cancellationToken);
        return tenantId;
    }

    private static string ScheduleDispatchJob(long messageId, string scheduleType, DateTime? scheduledAtUtc)
    {
        if (string.Equals(scheduleType, "scheduled", StringComparison.OrdinalIgnoreCase) && scheduledAtUtc.HasValue)
        {
            var delay = scheduledAtUtc.Value.ToUniversalTime() - DateTime.UtcNow;
            if (delay < TimeSpan.Zero)
            {
                delay = TimeSpan.Zero;
            }

            return BackgroundJob.Schedule<MemberMessageReachDispatchJobRunner>(
                runner => runner.ExecuteAsync(messageId),
                delay);
        }

        return BackgroundJob.Enqueue<MemberMessageReachDispatchJobRunner>(runner => runner.ExecuteAsync(messageId));
    }

    private static MemberMessageReachListItemResponse MapMessageListItem(MemberMessageReachListItemDto source)
    {
        return new MemberMessageReachListItemResponse
        {
            MessageId = source.MessageId.ToString(),
            Title = source.Title,
            Channels = source.Channels.ToList(),
            AudienceText = source.AudienceText,
            EstimatedReachCount = source.EstimatedReachCount,
            Status = source.Status,
            SentAt = FormatDateTime(source.SentAt),
            ScheduledAt = FormatDateTime(source.ScheduledAt),
            OpenRate = source.OpenRate,
            ConversionRate = source.ConversionRate
        };
    }

    private static MemberMessageReachDetailResponse MapMessageDetail(MemberMessageReachDetailDto source)
    {
        return new MemberMessageReachDetailResponse
        {
            MessageId = source.MessageId.ToString(),
            TemplateId = source.TemplateId?.ToString(),
            Title = source.Title,
            Content = source.Content,
            Channels = source.Channels.ToList(),
            AudienceType = source.AudienceType,
            AudienceTags = source.AudienceTags.ToList(),
            AudienceText = source.AudienceText,
            EstimatedReachCount = source.EstimatedReachCount,
            ScheduleType = source.ScheduleType,
            ScheduledAt = FormatDateTime(source.ScheduledAt),
            Status = source.Status,
            SentAt = FormatDateTime(source.SentAt),
            SentCount = source.SentCount,
            ReadCount = source.ReadCount,
            ConvertedCount = source.ConvertedCount,
            OpenRate = source.OpenRate,
            ConversionRate = source.ConversionRate,
            LastError = source.LastError,
            Recipients = source.Recipients.Select(item => new MemberMessageReachRecipientResponse
            {
                MemberId = item.MemberId.ToString(),
                Channel = item.Channel,
                Status = item.Status,
                Mobile = item.Mobile,
                OpenId = item.OpenId,
                SentAt = FormatDateTime(item.SentAt),
                ReadAt = FormatDateTime(item.ReadAt),
                ConvertedAt = FormatDateTime(item.ConvertedAt),
                ErrorMessage = item.ErrorMessage
            }).ToList()
        };
    }

    private static MemberMessageDispatchMetaResponse MapDispatchMeta(MemberMessageDispatchMetaDto source)
    {
        return new MemberMessageDispatchMetaResponse
        {
            MessageId = source.MessageId.ToString(),
            Status = source.Status,
            ScheduleType = source.ScheduleType,
            ScheduledAt = FormatDateTime(source.ScheduledAt),
            HangfireJobId = source.HangfireJobId
        };
    }

    private static MemberMessageTemplateResponse MapTemplate(MemberMessageTemplateDto source)
    {
        return new MemberMessageTemplateResponse
        {
            TemplateId = source.TemplateId.ToString(),
            Name = source.Name,
            Category = source.Category,
            Content = source.Content,
            UsageCount = source.UsageCount,
            LastUsedAt = FormatDateTime(source.LastUsedAt)
        };
    }

    private static string? FormatDateTime(DateTime? value)
    {
        return value.HasValue
            ? value.Value.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)
            : null;
    }
}
