using Microsoft.Extensions.Options;
using System.Net.Http.Json;
using System.Text.Json.Serialization;
using TakeoutSaaS.Application.Identity.Abstractions;
using TakeoutSaaS.Infrastructure.Identity.Options;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;

namespace TakeoutSaaS.Infrastructure.Identity.Services;

/// <summary>
/// 微信 code2Session 实现
/// </summary>
public sealed class WeChatAuthService(HttpClient httpClient, IOptions<WeChatMiniOptions> options) : IWeChatAuthService
{
    private readonly WeChatMiniOptions _options = options.Value;

    /// <summary>
    /// 调用微信接口完成 code2Session。
    /// </summary>
    /// <param name="code">临时登录凭证 code。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>微信会话信息。</returns>
    public async Task<WeChatSessionInfo> Code2SessionAsync(string code, CancellationToken cancellationToken = default)
    {
        // 1. 拼装请求地址
        var requestUri = $"sns/jscode2session?appid={Uri.EscapeDataString(_options.AppId)}&secret={Uri.EscapeDataString(_options.Secret)}&js_code={Uri.EscapeDataString(code)}&grant_type=authorization_code";
        using var response = await httpClient.GetAsync(requestUri, cancellationToken);
        response.EnsureSuccessStatusCode();

        // 2. 读取响应
        var payload = await response.Content.ReadFromJsonAsync<WeChatSessionResponse>(cancellationToken: cancellationToken);
        if (payload == null)
        {
            throw new BusinessException(ErrorCodes.Unauthorized, "微信登录失败：响应为空");
        }

        // 3. 校验错误码
        if (payload.ErrorCode.HasValue && payload.ErrorCode.Value != 0)
        {
            var message = string.IsNullOrWhiteSpace(payload.ErrorMessage)
                ? $"微信登录失败，错误码：{payload.ErrorCode}"
                : payload.ErrorMessage;
            throw new BusinessException(ErrorCodes.Unauthorized, message);
        }

        // 4. 校验必要字段
        if (string.IsNullOrWhiteSpace(payload.OpenId) || string.IsNullOrWhiteSpace(payload.SessionKey))
        {
            throw new BusinessException(ErrorCodes.Unauthorized, "微信登录失败：返回数据无效");
        }

        // 5. 组装会话信息
        return new WeChatSessionInfo
        {
            OpenId = payload.OpenId,
            UnionId = payload.UnionId,
            SessionKey = payload.SessionKey
        };
    }

    private sealed class WeChatSessionResponse
    {
        [JsonPropertyName("openid")]
        public string? OpenId { get; set; }

        [JsonPropertyName("unionid")]
        public string? UnionId { get; set; }

        [JsonPropertyName("session_key")]
        public string? SessionKey { get; set; }

        [JsonPropertyName("errcode")]
        public int? ErrorCode { get; set; }

        [JsonPropertyName("errmsg")]
        public string? ErrorMessage { get; set; }
    }
}
