using MediatR;
using TakeoutSaaS.Application.App.Tenants.Commands;
using TakeoutSaaS.Application.App.Tenants.Dto;
using TakeoutSaaS.Application.App.Tenants.Targeting;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Tenants.Handlers;

/// <summary>
/// 创建公告处理器。
/// </summary>
public sealed class CreateTenantAnnouncementCommandHandler(
    ITenantAnnouncementRepository announcementRepository,
    ITenantProvider tenantProvider,
    ICurrentUserAccessor currentUserAccessor)
    : IRequestHandler<CreateTenantAnnouncementCommand, TenantAnnouncementDto>
{
    /// <summary>
    /// 处理创建租户公告请求。
    /// </summary>
    /// <param name="request">创建命令。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>公告 DTO。</returns>
    public async Task<TenantAnnouncementDto> Handle(CreateTenantAnnouncementCommand request, CancellationToken cancellationToken)
    {
        // 1. 校验租户上下文（租户端禁止跨租户/系统公告）
        var currentTenantId = tenantProvider.GetCurrentTenantId();
        if (currentTenantId <= 0)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "缺少租户标识");
        }

        // 2. (空行后) 兼容旧调用：若传入 TenantId，则必须与当前租户一致
        if (request.TenantId > 0 && request.TenantId != currentTenantId)
        {
            throw new BusinessException(ErrorCodes.Forbidden, "无权创建其他租户公告");
        }

        // 3. (空行后) 校验标题与内容
        if (string.IsNullOrWhiteSpace(request.Title) || string.IsNullOrWhiteSpace(request.Content))
        {
            throw new BusinessException(ErrorCodes.ValidationFailed, "公告标题和内容不能为空");
        }

        // 4. (空行后) 校验公告发布范围：租户端仅允许租户公告
        if (request.PublisherScope != PublisherScope.Tenant)
        {
            throw new BusinessException(ErrorCodes.ValidationFailed, "租户端仅允许创建租户公告");
        }

        if (string.IsNullOrWhiteSpace(request.TargetType))
        {
            throw new BusinessException(ErrorCodes.ValidationFailed, "目标受众类型不能为空");
        }
        // 4.1 (空行后) 校验目标受众类型：租户端禁止跨租户目标类型
        if (!TenantAnnouncementTargetTypePolicy.IsAllowed(request.TargetType))
        {
            throw new BusinessException(ErrorCodes.ValidationFailed, "租户端不支持该目标受众类型");
        }

        if (request.EffectiveTo.HasValue && request.EffectiveFrom >= request.EffectiveTo.Value)
        {
            throw new BusinessException(ErrorCodes.ValidationFailed, "生效开始时间必须早于结束时间");
        }

        // 5. (空行后) 构建公告实体
        var tenantId = currentTenantId;
        var publisherUserId = currentUserAccessor.UserId == 0 ? (long?)null : currentUserAccessor.UserId;
        // 5.1 (空行后) 规范化目标类型，避免写入脏数据
        var normalizedTargetType = TenantAnnouncementTargetTypePolicy.Normalize(request.TargetType);
        var announcement = new TenantAnnouncement
        {
            TenantId = tenantId,
            Title = request.Title.Trim(),
            Content = request.Content,
            AnnouncementType = request.AnnouncementType,
            Priority = request.Priority,
            EffectiveFrom = request.EffectiveFrom,
            EffectiveTo = request.EffectiveTo,
            PublisherScope = request.PublisherScope,
            PublisherUserId = publisherUserId,
            Status = AnnouncementStatus.Draft,
            TargetType = normalizedTargetType,
            TargetParameters = request.TargetParameters
        };

        // 6. (空行后) 持久化并返回 DTO
        await announcementRepository.AddAsync(announcement, cancellationToken);
        await announcementRepository.SaveChangesAsync(cancellationToken);

        return announcement.ToDto(false, null);
    }
}
