package com.zhentao.service.impl;

import com.zhentao.service.WeChatService;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.type.TypeReference;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@Service
public class WeChatServiceImpl implements WeChatService {
    private static final Logger log = LoggerFactory.getLogger(WeChatServiceImpl.class);

    @Value("${wechat.mock.enabled:false}")
    private boolean mockEnabled;

    @Value("${wechat.appid:}")
    private String appId;

    @Value("${wechat.secret:}")
    private String secret;

    @Value("${wechat.api.jscode2session:https://api.weixin.qq.com/sns/jscode2session}")
    private String jscode2sessionUrl;

    @Value("${wechat.api.token:https://api.weixin.qq.com/cgi-bin/token}")
    private String tokenUrl;

    @Value("${wechat.api.getphone:https://api.weixin.qq.com/wxa/business/getuserphonenumber}")
    private String getPhoneUrl;

    @Override
    public Map<String, Object> code2Session(String code) {
        log.info("=== 开始调用微信 code2Session ===");
        log.info("接收到的 code: {}", code);
        log.info("code 长度: {}", code != null ? code.length() : 0);
        log.info("Mock 模式: {}", mockEnabled);
        
        Map<String, Object> result = new HashMap<>();
        if (code == null || code.trim().isEmpty()) {
            log.error("❌ code 为空");
            result.put("errcode", 400);
            result.put("errmsg", "code 不能为空");
            return result;
        }
        
        // 开发环境 Mock：无需真实 appid/secret 与外网请求
        if (mockEnabled) {
            log.info("✅ 使用 Mock 模式");
            Map<String, Object> mock = new HashMap<>();
            mock.put("errcode", 0);
            mock.put("openid", "mock_openid_" + code.trim());
            mock.put("session_key", "mock_session_key_" + code.trim());
            mock.put("unionid", null);
            return mock;
        }
        
        if (appId == null || appId.isEmpty() || secret == null || secret.isEmpty()) {
            log.error("❌ 未配置 appid 或 secret");
            log.error("appId: {}", appId != null ? (appId.isEmpty() ? "空字符串" : "已配置") : "null");
            log.error("secret: {}", secret != null ? (secret.isEmpty() ? "空字符串" : "已配置") : "null");
            result.put("errcode", 500);
            result.put("errmsg", "未配置 wechat.appid/secret");
            return result;
        }
        
        log.info("✅ 配置检查通过");
        log.info("appId: {}", appId);
        log.info("secret: {}...", secret.substring(0, Math.min(8, secret.length())));
        
        String url = String.format("%s?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                jscode2sessionUrl, appId, secret, code.trim());
        log.info("请求URL: {}", url.replace(secret, "***"));
        
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            HttpGet get = new HttpGet(url);
            log.info("发送HTTP请求到微信服务器...");
            
            try (CloseableHttpResponse resp = client.execute(get)) {
                int statusCode = resp.getStatusLine().getStatusCode();
                log.info("HTTP状态码: {}", statusCode);
                
                String body = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
                log.info("微信返回原始响应: {}", body);
                
                if (body == null || body.isEmpty()) {
                    log.error("❌ 微信返回空响应");
                    Map<String, Object> err = new HashMap<>();
                    err.put("errcode", 500);
                    err.put("errmsg", "微信返回空响应");
                    return err;
                }
                
                ObjectMapper mapper = new ObjectMapper();
                Map<String, Object> parsed = mapper.readValue(body, new TypeReference<Map<String, Object>>(){});
                
                // 检查是否有错误
                if (parsed.containsKey("errcode")) {
                    Integer errcode = (Integer) parsed.get("errcode");
                    if (errcode != 0) {
                        String errmsg = (String) parsed.get("errmsg");
                        log.error("❌ 微信接口返回错误");
                        log.error("错误码: {}", errcode);
                        log.error("错误信息: {}", errmsg);
                        
                        // 针对常见错误给出提示
                        if (errcode == 40029) {
                            log.error("提示: code 无效，可能原因：");
                            log.error("  1. code 已被使用过（每个 code 只能使用一次）");
                            log.error("  2. code 已过期（5分钟有效期）");
                            log.error("  3. code 与 appid 不匹配");
                        } else if (errcode == 40163) {
                            log.error("提示: code 已被使用");
                        }
                    } else {
                        log.info("✅ 微信接口调用成功");
                        log.info("openid: {}", parsed.get("openid"));
                    }
                }
                
                return parsed != null ? parsed : new HashMap<>();
            }
        } catch (Exception e) {
            log.error("❌ 调用 jscode2session 异常", e);
            Map<String, Object> err = new HashMap<>();
            err.put("errcode", 500);
            err.put("errmsg", "调用 jscode2session 异常:" + e.getMessage());
            return err;
        }
    }

    @Override
    public String decryptPhone(String sessionKey, String iv, String encryptedData) {
        // 为避免引入复杂依赖，这里暂返回 null。
        // 如果前端走 getPhoneNumber 新版接口，建议将手机号直接传至后端，无需解密。
        return null;
    }

    @Override
    public String getAccessToken() {
        // 开发环境 Mock：直接返回固定 token
        if (mockEnabled) {
            return "mock_access_token";
        }
        if (appId == null || appId.isEmpty() || secret == null || secret.isEmpty()) {
            return null;
        }
        String url = String.format("%s?grant_type=client_credential&appid=%s&secret=%s", tokenUrl, appId, secret);
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            HttpGet get = new HttpGet(url);
            try (CloseableHttpResponse resp = client.execute(get)) {
                String body = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
                if (body == null || body.isEmpty()) return null;
                ObjectMapper mapper = new ObjectMapper();
                Map<String, Object> parsed = mapper.readValue(body, new TypeReference<Map<String, Object>>(){});
                Object token = parsed.get("access_token");
                return token != null ? String.valueOf(token) : null;
            }
        } catch (Exception e) {
            log.error("获取 access_token 失败", e);
            return null;
        }
    }

    @Override
    public String getUserPhoneByCode(String code) {
        log.info("=== 开始获取微信手机号 ===");
        log.info("接收到的 phoneCode: {}", code);
        log.info("Mock 模式: {}", mockEnabled);
        
        // 开发环境 Mock：返回演示手机号
        if (mockEnabled) {
            log.info("✅ 使用 Mock 模式，返回测试手机号");
            return "13800138000";
        }
        
        if (code == null || code.trim().isEmpty()) {
            log.error("❌ phoneCode 为空");
            return null;
        }
        
        log.info("获取 access_token...");
        String accessToken = getAccessToken();
        if (accessToken == null) {
            log.error("❌ 获取 access_token 失败");
            return null;
        }
        log.info("✅ access_token 获取成功: {}...", accessToken.substring(0, Math.min(20, accessToken.length())));
        
        String url = String.format("%s?access_token=%s", getPhoneUrl, accessToken);
        log.info("请求URL: {}", url.replace(accessToken, "***"));
        
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            // 微信该接口要求 POST JSON：{"code":"xxx"}
            org.apache.http.client.methods.HttpPost post = new org.apache.http.client.methods.HttpPost(url);
            post.setHeader("Content-Type", "application/json;charset=UTF-8");
            String payload = "{\"code\":\"" + code.trim() + "\"}";
            log.info("请求体: {}", payload);
            post.setEntity(new org.apache.http.entity.StringEntity(payload, StandardCharsets.UTF_8));
            
            log.info("发送HTTP POST请求到微信服务器...");
            try (CloseableHttpResponse resp = client.execute(post)) {
                int statusCode = resp.getStatusLine().getStatusCode();
                log.info("HTTP状态码: {}", statusCode);
                
                String body = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
                log.info("微信返回原始响应: {}", body);
                
                if (body == null || body.isEmpty()) {
                    log.error("❌ 微信返回空响应");
                    return null;
                }
                
                ObjectMapper mapper = new ObjectMapper();
                Map<String, Object> parsed = mapper.readValue(body, new TypeReference<Map<String, Object>>(){});
                
                // 检查错误码
                Object errcode = parsed.get("errcode");
                if (errcode != null) {
                    int errcodeInt = ((Number) errcode).intValue();
                    if (errcodeInt != 0) {
                        String errmsg = parsed.get("errmsg") != null ? String.valueOf(parsed.get("errmsg")) : "未知错误";
                        log.error("❌ 微信接口返回错误");
                        log.error("错误码: {}", errcodeInt);
                        log.error("错误信息: {}", errmsg);
                        return null;
                    }
                }
                
                // 微信返回结构：{"errcode":0,"errmsg":"ok","phone_info":{"phoneNumber":"xxxx","purePhoneNumber":"xxxx","countryCode":"86","watermark":{...}}}
                Object phoneInfo = parsed.get("phone_info");
                if (phoneInfo instanceof Map) {
                    Map<String, Object> phoneMap = (Map<String, Object>) phoneInfo;
                    Object phone = phoneMap.get("phoneNumber");
                    if (phone == null) phone = phoneMap.get("purePhoneNumber");
                    
                    if (phone != null) {
                        String phoneStr = String.valueOf(phone);
                        log.info("✅ 成功获取手机号: {}", phoneStr);
                        return phoneStr;
                    } else {
                        log.error("❌ phone_info 中没有 phoneNumber 或 purePhoneNumber");
                        log.error("phone_info 内容: {}", phoneMap);
                    }
                } else {
                    log.error("❌ 响应中没有 phone_info 字段或格式错误");
                    log.error("响应内容: {}", parsed);
                }
            }
        } catch (Exception e) {
            log.error("❌ 通过 code 获取手机号异常", e);
        }
        return null;
    }

}