using MediatR;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Tenants.Commands;
using TakeoutSaaS.Application.App.Tenants.Dto;
using TakeoutSaaS.Application.Identity.Commands;
using TakeoutSaaS.Domain.Identity.Entities;
using TakeoutSaaS.Domain.Identity.Repositories;
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.Ids;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Tenants.Handlers;

/// <summary>
/// 后台手动新增租户处理器。
/// </summary>
public sealed class CreateTenantManuallyCommandHandler(
    ITenantRepository tenantRepository,
    ITenantPackageRepository tenantPackageRepository,
    IIdentityUserRepository identityUserRepository,
    IRoleRepository roleRepository,
    IPasswordHasher<IdentityUser> passwordHasher,
    IIdGenerator idGenerator,
    IMediator mediator,
    ITenantContextAccessor tenantContextAccessor,
    ICurrentUserAccessor currentUserAccessor,
    ILogger<CreateTenantManuallyCommandHandler> logger)
    : IRequestHandler<CreateTenantManuallyCommand, TenantDetailDto>
{
    /// <inheritdoc />
    public async Task<TenantDetailDto> Handle(CreateTenantManuallyCommand request, CancellationToken cancellationToken)
    {
        // 1. 校验订阅时长
        if (request.DurationMonths <= 0)
        {
            throw new BusinessException(ErrorCodes.ValidationFailed, "订阅时长必须大于 0");
        }

        // 2. 校验租户编码唯一性
        var normalizedCode = request.Code.Trim();
        if (await tenantRepository.ExistsByCodeAsync(normalizedCode, cancellationToken))
        {
            throw new BusinessException(ErrorCodes.Conflict, $"租户编码 {normalizedCode} 已存在");
        }

        // 3. (空行后) 校验联系人手机号唯一性（仅当填写时）
        if (!string.IsNullOrWhiteSpace(request.ContactPhone))
        {
            var normalizedPhone = request.ContactPhone.Trim();
            if (await tenantRepository.ExistsByContactPhoneAsync(normalizedPhone, cancellationToken))
            {
                throw new BusinessException(ErrorCodes.Conflict, $"手机号 {normalizedPhone} 已注册");
            }
        }

        // 4. (空行后) 校验管理员账号唯一性
        var normalizedAccount = request.AdminAccount.Trim();
        if (await identityUserRepository.ExistsByAccountAsync(normalizedAccount, cancellationToken))
        {
            throw new BusinessException(ErrorCodes.Conflict, $"账号 {normalizedAccount} 已存在");
        }

        // 5. (空行后) 校验套餐存在且可用
        var package = await tenantPackageRepository.FindByIdAsync(request.TenantPackageId, cancellationToken)
            ?? throw new BusinessException(ErrorCodes.NotFound, "套餐不存在");
        if (!package.IsActive)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "套餐未启用，无法绑定订阅");
        }

        // 6. (空行后) 计算订阅生效与到期时间（UTC）
        var now = DateTime.UtcNow;
        var subscriptionEffectiveFrom = request.SubscriptionEffectiveFrom ?? now;
        var subscriptionEffectiveTo = subscriptionEffectiveFrom.AddMonths(request.DurationMonths);

        // 7. (空行后) 构建租户与订阅
        var tenantId = idGenerator.NextId();
        var tenant = new Tenant
        {
            Id = tenantId,
            Code = normalizedCode,
            Name = request.Name.Trim(),
            ShortName = request.ShortName,
            LegalEntityName = request.LegalEntityName,
            Industry = request.Industry,
            LogoUrl = request.LogoUrl,
            CoverImageUrl = request.CoverImageUrl,
            Website = request.Website,
            Country = request.Country,
            Province = request.Province,
            City = request.City,
            Address = request.Address,
            ContactName = request.ContactName,
            ContactPhone = string.IsNullOrWhiteSpace(request.ContactPhone) ? null : request.ContactPhone.Trim(),
            ContactEmail = request.ContactEmail,
            Status = request.TenantStatus,
            EffectiveFrom = subscriptionEffectiveFrom,
            EffectiveTo = subscriptionEffectiveTo,
            SuspendedAt = request.SuspendedAt,
            SuspensionReason = request.SuspensionReason,
            Tags = request.Tags,
            Remarks = request.Remarks
        };

        // 8. (空行后) 构建订阅实体
        var subscription = new TenantSubscription
        {
            Id = idGenerator.NextId(),
            TenantId = tenantId,
            TenantPackageId = request.TenantPackageId,
            EffectiveFrom = subscriptionEffectiveFrom,
            EffectiveTo = subscriptionEffectiveTo,
            NextBillingDate = request.NextBillingDate ?? subscriptionEffectiveTo,
            Status = request.SubscriptionStatus,
            AutoRenew = request.AutoRenew,
            ScheduledPackageId = request.ScheduledPackageId,
            Notes = request.SubscriptionNotes
        };

        // 9. (空行后) 构建认证资料（默认直接通过）
        var actorName = currentUserAccessor.IsAuthenticated
            ? $"user:{currentUserAccessor.UserId}"
            : "system";

        var verification = new TenantVerificationProfile
        {
            Id = idGenerator.NextId(),
            TenantId = tenantId,
            Status = request.VerificationStatus,
            BusinessLicenseNumber = request.BusinessLicenseNumber,
            BusinessLicenseUrl = request.BusinessLicenseUrl,
            LegalPersonName = request.LegalPersonName,
            LegalPersonIdNumber = request.LegalPersonIdNumber,
            LegalPersonIdFrontUrl = request.LegalPersonIdFrontUrl,
            LegalPersonIdBackUrl = request.LegalPersonIdBackUrl,
            BankAccountName = request.BankAccountName,
            BankAccountNumber = request.BankAccountNumber,
            BankName = request.BankName,
            AdditionalDataJson = request.AdditionalDataJson,
            SubmittedAt = request.SubmittedAt ?? now,
            ReviewedAt = request.ReviewedAt ?? now,
            ReviewedBy = currentUserAccessor.UserId == 0 ? null : currentUserAccessor.UserId,
            ReviewedByName = string.IsNullOrWhiteSpace(request.ReviewedByName) ? actorName : request.ReviewedByName,
            ReviewRemarks = request.ReviewRemarks
        };

        // 10. (空行后) 写入审计日志与订阅历史
        await tenantRepository.AddAuditLogAsync(new TenantAuditLog
        {
            TenantId = tenantId,
            Action = TenantAuditAction.RegistrationSubmitted,
            Title = "后台手动创建",
            Description = $"绑定套餐 {request.TenantPackageId}，订阅 {request.DurationMonths} 月",
            OperatorId = currentUserAccessor.UserId == 0 ? null : currentUserAccessor.UserId,
            OperatorName = actorName,
            PreviousStatus = null,
            CurrentStatus = tenant.Status
        }, cancellationToken);

        await tenantRepository.AddAuditLogAsync(new TenantAuditLog
        {
            TenantId = tenantId,
            Action = TenantAuditAction.SubscriptionUpdated,
            Title = "订阅初始化",
            Description = $"生效：{subscription.EffectiveFrom:yyyy-MM-dd HH:mm:ss}，到期：{subscription.EffectiveTo:yyyy-MM-dd HH:mm:ss}",
            OperatorId = currentUserAccessor.UserId == 0 ? null : currentUserAccessor.UserId,
            OperatorName = actorName,
            PreviousStatus = null,
            CurrentStatus = tenant.Status
        }, cancellationToken);

        await tenantRepository.AddAuditLogAsync(new TenantAuditLog
        {
            TenantId = tenantId,
            Action = TenantAuditAction.VerificationApproved,
            Title = "认证已通过",
            Description = request.ReviewRemarks,
            OperatorId = currentUserAccessor.UserId == 0 ? null : currentUserAccessor.UserId,
            OperatorName = actorName,
            PreviousStatus = null,
            CurrentStatus = tenant.Status
        }, cancellationToken);

        await tenantRepository.AddSubscriptionHistoryAsync(new TenantSubscriptionHistory
        {
            TenantId = tenantId,
            TenantSubscriptionId = subscription.Id,
            FromPackageId = request.TenantPackageId,
            ToPackageId = request.TenantPackageId,
            ChangeType = SubscriptionChangeType.New,
            EffectiveFrom = subscription.EffectiveFrom,
            EffectiveTo = subscription.EffectiveTo,
            Amount = null,
            Currency = null,
            Notes = request.SubscriptionNotes
        }, cancellationToken);

        // 11. (空行后) 持久化租户、订阅与认证资料
        await tenantRepository.AddTenantAsync(tenant, cancellationToken);
        await tenantRepository.AddSubscriptionAsync(subscription, cancellationToken);
        await tenantRepository.UpsertVerificationProfileAsync(verification, cancellationToken);
        await tenantRepository.SaveChangesAsync(cancellationToken);

        // 12. (空行后) 临时切换租户上下文，保证身份与权限写入正确
        var previousContext = tenantContextAccessor.Current;
        tenantContextAccessor.Current = new TenantContext(tenant.Id, tenant.Code, "manual-create");
        try
        {
            // 13. 创建租户管理员账号
            var adminUser = new IdentityUser
            {
                TenantId = tenant.Id,
                Account = normalizedAccount,
                DisplayName = request.AdminDisplayName.Trim(),
                PasswordHash = string.Empty,
                Phone = string.IsNullOrWhiteSpace(request.ContactPhone) ? null : request.ContactPhone.Trim(),
                Email = string.IsNullOrWhiteSpace(request.ContactEmail) ? null : request.ContactEmail.Trim(),
                MerchantId = request.AdminMerchantId,
                Avatar = request.AdminAvatar
            };
            adminUser.PasswordHash = passwordHasher.HashPassword(adminUser, request.AdminPassword);
            await identityUserRepository.AddAsync(adminUser, cancellationToken);
            await identityUserRepository.SaveChangesAsync(cancellationToken);

            // 14. (空行后) 初始化租户管理员角色模板并绑定角色
            await mediator.Send(new InitializeRoleTemplatesCommand
            {
                TemplateCodes = new[] { "tenant-admin" }
            }, cancellationToken);

            var tenantAdminRole = await roleRepository.FindByCodeAsync("tenant-admin", tenant.Id, cancellationToken);
            if (tenantAdminRole != null)
            {
                await mediator.Send(new AssignUserRolesCommand
                {
                    UserId = adminUser.Id,
                    RoleIds = new[] { tenantAdminRole.Id }
                }, cancellationToken);
            }

            // 15. (空行后) 回写租户所有者账号
            tenant.PrimaryOwnerUserId = adminUser.Id;
            await tenantRepository.UpdateTenantAsync(tenant, cancellationToken);
            await tenantRepository.SaveChangesAsync(cancellationToken);
        }
        finally
        {
            // 16. 恢复上下文
            tenantContextAccessor.Current = previousContext;
        }

        // 17. (空行后) 返回创建结果
        logger.LogInformation("已后台手动创建租户 {TenantCode}", tenant.Code);

        return new TenantDetailDto
        {
            Tenant = TenantMapping.ToDto(tenant, subscription, verification),
            Verification = verification.ToVerificationDto(),
            Subscription = subscription.ToSubscriptionDto(),
            Package = package.ToDto()
        };
    }
}
