using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using QYZH.InteractiveMagazine.Common.Helpers;
using QYZH.InteractiveMagazine.Infrastructure.Auth;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Entity;
using QYZH.InteractiveMagazine.Models.Enum;
using QYZH.InteractiveMagazine.Models.Settings;
using QYZH.InteractiveMagazine.Models.WeChat;
using QYZH.InteractiveMagazine.Repository;

namespace QYZH.InteractiveMagazine.Service;

/// <summary>
/// 微信小程序认证服务实现
/// 登录基于 WxUser 表（微信身份），多用户管理基于 Users 表（角色/子用户）
/// </summary>
public class WeChatAuthService(
    BaseRepository<WxUser> wxUserRepository,
    IConfiguration configuration,
    ILogger<WeChatAuthService> logger,
    IPetService petService)
    : BaseRepository<WxUser>, IWeChatAuthService
{
    private const string AccessTokenCacheKey = "InteractiveMagazine:WeChat:AccessToken";
    private const string Code2SessionUrl = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code";
    private const string GetAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
    private const string GetPhoneNumberUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={0}";

    /// <summary>
    /// 微信小程序登录
    /// 流程: code2session → 查找/创建 WxUser → 更新手机号 → 查询 Users 列表 → 生成 Token
    /// </summary>
    public async Task<WeChatLoginOutput> LoginAsync(WeChatLoginInput input)
    {
        logger.LogInformation("微信小程序登录");

        if (string.IsNullOrWhiteSpace(input.Code))
            throw new BusinessException("微信登录凭证 code 不能为空", ResultCode.BAD_REQUEST);

        var weChatSettings = GetWeChatSettings();

        // 1. 调用微信 code2session
        var wxResponse = await CallCode2SessionAsync(weChatSettings, input.Code);
        if (wxResponse == null || wxResponse.ErrCode != 0 || string.IsNullOrWhiteSpace(wxResponse.OpenId))
        {
            var errMsg = wxResponse?.ErrMsg ?? "未知错误";
            logger.LogWarning("微信 code2session 接口调用失败，errcode: {ErrCode}, errmsg: {ErrMsg}", wxResponse?.ErrCode, errMsg);
            throw new BusinessException($"微信登录失败：{errMsg}", ResultCode.BAD_REQUEST);
        }

        logger.LogInformation("微信 code2session 成功，OpenId: {OpenId}", wxResponse.OpenId);

        // 2. 获取手机号（如果传入了 PhoneCode）
        string? phone = null;
        if (!string.IsNullOrWhiteSpace(input.PhoneCode))
        {
            phone = await GetPhoneNumberAsync(weChatSettings, input.PhoneCode);
            logger.LogInformation("获取手机号，OpenId: {OpenId}, Phone: {Phone}", wxResponse.OpenId, phone ?? "null");
        }

        // 3. 查找或创建 WxUser
        var wxUser = await wxUserRepository.Context.Queryable<WxUser>()
            .Where(w => w.OpenId == wxResponse.OpenId && !w.IsDeleted)
            .FirstAsync();

        if (wxUser == null)
        {
            // 首次登录：仅创建 WxUser，不自动创建 User（用户需手动创建）
            wxUser = new WxUser
            {
                Name = $"wx_{wxResponse.OpenId[^8..]}",
                AvatarUrl = string.Empty,
                OpenId = wxResponse.OpenId,
                UnionId = wxResponse.UnionId,
                Phone = phone,
                Status = 1,
                IsDeleted = false,
                CreatedBy = "WeChat",
                CreatedAt = DateTime.Now,
                UpdatedBy = "WeChat",
                UpdatedAt = DateTime.Now
            };

            await wxUserRepository.InsertAsync(wxUser);


            logger.LogInformation("WxUser 创建成功，WxUserId: {WxUserId}, OpenId: {OpenId}", wxUser.Id, wxResponse.OpenId);
        }
        else
        {
            // 非首次登录：更新 UnionId 和手机号
            if (!string.IsNullOrWhiteSpace(wxResponse.UnionId) && string.IsNullOrWhiteSpace(wxUser.UnionId))
            {
                await wxUserRepository.Context.Updateable<WxUser>()
                    .SetColumns(w => w.UnionId == wxResponse.UnionId)
                    .Where(w => w.Id == wxUser.Id)
                    .ExecuteCommandAsync();
                wxUser.UnionId = wxResponse.UnionId;
            }

            if (!string.IsNullOrWhiteSpace(phone))
            {
                await wxUserRepository.Context.Updateable<WxUser>()
                    .SetColumns(w => w.Phone == phone)
                    .Where(w => w.Id == wxUser.Id)
                    .ExecuteCommandAsync();
                wxUser.Phone = phone;
                logger.LogInformation("更新 WxUser 手机号，WxUserId: {WxUserId}, Phone: {Phone}", wxUser.Id, phone);
            }
        }

        // 查询该 WxUser 下所有 Users（首次登录时为空列表）
        var users = await wxUserRepository.Context.Queryable<Users>()
            .Where(u => u.WxUserId == wxUser.Id && !u.IsDeleted)
            .ToListAsync();

        logger.LogInformation("微信登录成功，WxUserId: {WxUserId} 下存在 {Count} 个用户", wxUser.Id, users.Count);

        return await BuildLoginOutputAsync(wxUser, users);
    }

    /// <summary>
    /// 微信小程序快捷登录（通过 OpenId 直接登录）
    /// </summary>
    public async Task<WeChatLoginOutput> QuickLoginAsync(WeChatQuickLoginInput input)
    {
        logger.LogInformation("微信快捷登录，OpenId: {OpenId}", input.OpenId);

        if (string.IsNullOrWhiteSpace(input.OpenId))
            throw new BusinessException("OpenId 不能为空", ResultCode.BAD_REQUEST);

        var wxUser = await wxUserRepository.Context.Queryable<WxUser>()
            .Where(w => w.OpenId == input.OpenId && !w.IsDeleted)
            .FirstAsync();

        if (wxUser == null)
        {
            logger.LogWarning("快捷登录失败，OpenId: {OpenId} 下无 WxUser", input.OpenId);
            throw new BusinessException("未找到该微信账号关联的用户，请先完成注册", ResultCode.NOT_FOUND);
        }

        var users = await wxUserRepository.Context.Queryable<Users>()
            .Where(u => u.WxUserId == wxUser.Id && !u.IsDeleted)
            .ToListAsync();

        logger.LogInformation("快捷登录成功，WxUserId: {WxUserId}, {Count} 个用户", wxUser.Id, users.Count);

        return await BuildLoginOutputAsync(wxUser, users);
    }

    /// <summary>
    /// 切换用户（同一 WxUser 下切换 User 身份，重新生成 Token）
    /// </summary>
    public async Task<WeChatSwitchUserOutput> SwitchUserAsync(long wxUserId, long currentUserId, WeChatSwitchUserInput input)
    {
        logger.LogInformation("切换用户，WxUserId: {WxUserId}, 当前 UserId: {CurrentUserId}, 目标 UserId: {TargetUserId}",
            wxUserId, currentUserId, input.UserId);

        // 查询目标用户
        var targetUser = await wxUserRepository.Context.Queryable<Users>()
            .Where(u => u.Id == input.UserId && !u.IsDeleted)
            .FirstAsync();

        if (targetUser == null)
            throw new BusinessException("目标用户不存在", ResultCode.NOT_FOUND);

        // 校验目标用户属于同一 WxUser
        if (targetUser.WxUserId != wxUserId)
        {
            logger.LogWarning("切换用户失败，WxUserId 不匹配，当前: {Current}, 目标: {Target}", wxUserId, targetUser.WxUserId);
            throw new BusinessException("无法切换到该用户", ResultCode.FORBIDDEN);
        }

        if (targetUser.Status == (int)UserStatusEnum.Disabled)
            throw new BusinessException("目标账号已被禁用", ResultCode.FORBIDDEN);

        // 更新 IsLastOnline（清除所有，设置目标为 true）
        await wxUserRepository.Context.Updateable<Users>()
            .SetColumns(u => u.IsLastOnline == false)
            .Where(u => u.WxUserId == wxUserId && !u.IsDeleted)
            .ExecuteCommandAsync();

        await wxUserRepository.Context.Updateable<Users>()
            .SetColumns(u => u.IsLastOnline == true)
            .Where(u => u.Id == input.UserId && !u.IsDeleted)
            .ExecuteCommandAsync();

        logger.LogInformation("IsLastOnline 已更新，目标用户 {UserId} 设为 true", input.UserId);

        // 重新查询目标用户获取最新数据
        var refreshedUser = await wxUserRepository.Context.Queryable<Users>()
            .Where(u => u.Id == input.UserId && !u.IsDeleted)
            .FirstAsync();

        // 生成新 JWT Token（WxUserId + 新 UserId）
        var jwtSettings = GetJwtSettings();
        var token = JwtHelper.GenerateToken(wxUserId, refreshedUser.Id, refreshedUser.Name ?? string.Empty, jwtSettings);

        // 清除旧 Redis Token，写入新 Token
        await RedisHelper.DelAsync(JwtHelper.BuildWeChatTokenKey(wxUserId, currentUserId));
        await RedisHelper.SetAsync(JwtHelper.BuildWeChatTokenKey(wxUserId, refreshedUser.Id), token, TimeSpan.FromMinutes(jwtSettings.ExpiryMinutes));

        return new WeChatSwitchUserOutput
        {
            Token = token,
            User = MapUserToOutput(refreshedUser)
        };
    }

    /// <summary>
    /// 获取当前 WxUser 下所有用户列表
    /// </summary>
    public async Task<List<WxUserOutput>> GetUsersAsync(long wxUserId)
    {
        var users = await wxUserRepository.Context.Queryable<Users>()
            .Where(u => u.WxUserId == wxUserId && !u.IsDeleted)
            .OrderBy(u => u.IsLastOnline, SqlSugar.OrderByType.Desc)
            .OrderBy(u => u.CreatedAt, SqlSugar.OrderByType.Desc)
            .ToListAsync();

        return users.Select(MapUserToOutput).ToList();
    }

    /// <summary>
    /// 在当前 WxUser 下新增用户（wxUserId 来自 JWT）
    /// </summary>
    public async Task<WxUserOutput> CreateUserAsync(long wxUserId, CreateChildUserInput input)
    {
        logger.LogInformation("新增用户，WxUserId: {WxUserId}, Name: {Name}", wxUserId, input.Name);

        if (string.IsNullOrWhiteSpace(input.Name))
            throw new BusinessException("昵称不能为空", ResultCode.BAD_REQUEST);

        // 校验 WxUser 是否存在
        var wxUser = await wxUserRepository.Context.Queryable<WxUser>()
            .Where(w => w.Id == wxUserId)
            .FirstAsync();

        if (wxUser == null)
            throw new BusinessException("微信用户不存在", ResultCode.NOT_FOUND);

        // 创建新用户
        var newUser = new Users
        {
            WxUserId = wxUserId,
            Name = input.Name.Trim(),
            AvatarUrl = input.AvatarUrl ?? string.Empty,
            Type = UsersTypeEnum.Normal,
            GrowthPoints = 0,
            Points = 0,
            IsLastOnline = false,
            Status = (int)UserStatusEnum.Active,
            IsDeleted = false,
            CreatedBy = wxUserId.ToString(),
            CreatedAt = DateTime.Now,
            UpdatedBy = wxUserId.ToString(),
            UpdatedAt = DateTime.Now
        };

        await wxUserRepository.Context.Insertable(newUser).ExecuteReturnIdentityAsync();

        logger.LogInformation("新用户创建成功，UserId: {UserId}, WxUserId: {WxUserId}, Name: {Name}",
            newUser.Id, wxUserId, input.Name);

        // 为新用户创建默认宠物
        try { await petService.CreateDefaultPetAsync(newUser.Id); }
        catch (Exception ex) { logger.LogError(ex, "新用户创建默认宠物失败，UserId: {UserId}", newUser.Id); }

        return MapUserToOutput(newUser);
    }

    /// <summary>
    /// 修改家长名字（WxUser.Name）
    /// </summary>
    public async Task<WxUserInfoOutput> UpdateWxUserNameAsync(long wxUserId, UpdateWxUserNameInput input)
    {
        logger.LogInformation("修改家长名字，WxUserId: {WxUserId}, NewName: {Name}", wxUserId, input.Name);

        if (string.IsNullOrWhiteSpace(input.Name))
            throw new BusinessException("名字不能为空", ResultCode.BAD_REQUEST);

        var wxUser = await wxUserRepository.Context.Queryable<WxUser>()
            .Where(w => w.Id == wxUserId && !w.IsDeleted)
            .FirstAsync();

        if (wxUser == null)
            throw new BusinessException("微信用户不存在", ResultCode.NOT_FOUND);

        await wxUserRepository.Context.Updateable<WxUser>()
            .SetColumns(w => w.Name == input.Name.Trim())
            .SetColumns(w => w.UpdatedAt == DateTime.Now)
            .SetColumns(w => w.UpdatedBy == wxUserId.ToString())
            .Where(w => w.Id == wxUserId)
            .ExecuteCommandAsync();

        wxUser.Name = input.Name.Trim();

        logger.LogInformation("家长名字修改成功，WxUserId: {WxUserId}, NewName: {Name}", wxUserId, input.Name);

        return new WxUserInfoOutput
        {
            Id = wxUser.Id,
            OpenId = wxUser.OpenId,
            UnionId = wxUser.UnionId,
            Name = wxUser.Name,
            AvatarUrl = wxUser.AvatarUrl,
            Phone = wxUser.Phone
        };
    }

    #region 私有辅助方法

    /// <summary>
    /// 构建登录输出（JWT 同时携带 WxUserId 和当前激活 UserId）
    /// </summary>
    private async Task<WeChatLoginOutput> BuildLoginOutputAsync(WxUser wxUser, List<Users> users)
    {
        var activeUser = users.FirstOrDefault(u => u.IsLastOnline) ?? users.FirstOrDefault();

        var userId = activeUser?.Id ?? 0L;
        var userName = activeUser?.Name ?? wxUser.Name ?? wxUser.OpenId;

        var jwtSettings = GetJwtSettings();
        var token = JwtHelper.GenerateToken(wxUser.Id, userId, userName, jwtSettings);

        await RedisHelper.SetAsync(JwtHelper.BuildWeChatTokenKey(wxUser.Id, userId), token, TimeSpan.FromMinutes(jwtSettings.ExpiryMinutes));

        return new WeChatLoginOutput
        {
            Token = token,
            CurrentUserId = userId,
            WxUser = new WxUserInfoOutput
            {
                Id = wxUser.Id,
                OpenId = wxUser.OpenId,
                UnionId = wxUser.UnionId,
                Name = wxUser.Name,
                AvatarUrl = wxUser.AvatarUrl,
                Phone = wxUser.Phone
            },
            Users = users.Select(MapUserToOutput).ToList()
        };
    }

    /// <summary>
    /// 调用微信 code2session 接口
    /// </summary>
    private async Task<WxCode2SessionResponse?> CallCode2SessionAsync(WeChatSettings settings, string code)
    {
        var url = string.Format(Code2SessionUrl, settings.AppId, settings.AppSecret, code);
        try
        {
            return await HttpHelper.GetAsync<WxCode2SessionResponse>(url);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "调用微信 code2session 接口异常，URL: {Url}", url);
            throw new BusinessException("微信服务请求失败，请稍后重试", ResultCode.GLOBAL_ERROR);
        }
    }

    /// <summary>
    /// 获取微信 access_token（带 Redis 缓存）
    /// </summary>
    private async Task<string> GetAccessTokenAsync(WeChatSettings settings)
    {
        var cachedToken = await RedisHelper.GetAsync(AccessTokenCacheKey);
        if (!string.IsNullOrWhiteSpace(cachedToken))
            return cachedToken;

        var url = string.Format(GetAccessTokenUrl, settings.AppId, settings.AppSecret);
        var response = await HttpHelper.GetAsync<WxAccessTokenResponse>(url);

        if (response == null || response.ErrCode != 0 || string.IsNullOrWhiteSpace(response.AccessToken))
        {
            var errMsg = response?.ErrMsg ?? "未知错误";
            logger.LogError("获取微信 access_token 失败，errcode: {ErrCode}, errmsg: {ErrMsg}", response?.ErrCode, errMsg);
            throw new BusinessException("微信服务请求失败，请稍后重试", ResultCode.GLOBAL_ERROR);
        }

        var expiresIn = response.ExpiresIn > 300 ? response.ExpiresIn - 300 : response.ExpiresIn;
        await RedisHelper.SetAsync(AccessTokenCacheKey, response.AccessToken, TimeSpan.FromSeconds(expiresIn));

        logger.LogInformation("获取微信 access_token 成功，有效期: {ExpiresIn} 秒", expiresIn);
        return response.AccessToken;
    }

    /// <summary>
    /// 通过 phone_code 获取微信用户手机号
    /// </summary>
    private async Task<string?> GetPhoneNumberAsync(WeChatSettings settings, string phoneCode)
    {
        try
        {
            var accessToken = await GetAccessTokenAsync(settings);
            var url = string.Format(GetPhoneNumberUrl, accessToken);
            var response = await HttpHelper.PostAsync<WxPhoneNumberResponse>(url, new { code = phoneCode });

            if (response == null || response.ErrCode != 0 || response.PhoneInfo == null)
            {
                var errMsg = response?.ErrMsg ?? "未知错误";
                logger.LogWarning("获取手机号失败，errcode: {ErrCode}, errmsg: {ErrMsg}", response?.ErrCode, errMsg);
                return null;
            }

            return response.PhoneInfo.PurePhoneNumber ?? response.PhoneInfo.PhoneNumber;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "调用微信获取手机号接口异常");
            return null;
        }
    }

    /// <summary>
    /// Users 实体映射为 WxUserOutput
    /// </summary>
    private static WxUserOutput MapUserToOutput(Users user)
    {
        return new WxUserOutput
        {
            Id = (long)user.Id,
            WxUserId = user.WxUserId,
            NickName = user.Name,
            AvatarUrl = user.AvatarUrl,
            Points = user.Points,
            GrowthPoints = user.GrowthPoints,
            Type = user.Type.ToString(),
            Status = user.Status.ToString(),
            IsLastOnline = user.IsLastOnline,
            CreatedAt = user.CreatedAt
        };
    }

    private WeChatSettings GetWeChatSettings()
    {
        var settings = configuration.GetSection("WeChatSettings").Get<WeChatSettings>();
        if (settings == null || string.IsNullOrWhiteSpace(settings.AppId) || string.IsNullOrWhiteSpace(settings.AppSecret))
        {
            logger.LogError("微信配置不完整，请检查 appsettings.json 中的 WeChatSettings 节点");
            throw new BusinessException("微信配置不完整，请联系系统管理员", ResultCode.GLOBAL_ERROR);
        }
        return settings;
    }

    private JwtSettings GetJwtSettings()
    {
        var jwtSettings = configuration.GetSection("JwtSettings").Get<JwtSettings>()
            ?? new JwtSettings
            {
                Issuer = "QYZH.InteractiveMagazine",
                Audience = "QYZH.InteractiveMagazine",
                SecretKey = "your-256-bit-secret-key-here-change-in-production",
                ExpiryMinutes = 120
            };

        if (string.IsNullOrWhiteSpace(jwtSettings.SecretKey))
            throw new BusinessException("JWT 配置不完整", ResultCode.GLOBAL_ERROR);

        return jwtSettings;
    }

    #endregion
}
