package com.haha.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.haha.common.enums.CommonStatus;
import com.haha.common.vo.Result;
import com.haha.entity.User;
import com.haha.service.LoginService;
import com.haha.service.UserService;
import com.haha.common.vo.LoginVO;
import com.haha.common.vo.UserVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

@Slf4j
@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private UserService userService;

    @Autowired
    private RestTemplate restTemplate;

    @Value("${wechat.miniapp.app-id:}")
    private String miniappAppId;

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

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    private static final Pattern SESSION_KEY_PATTERN = Pattern.compile("\"session_key\"\\s*:\\s*\"([^\"]+)\"");
    private static final Pattern ACCESS_TOKEN_PATTERN = Pattern.compile("\"access_token\"\\s*:\\s*\"([^\"]+)\"");
    private static final Pattern OPENID_PATTERN = Pattern.compile("\"openid\"\\s*:\\s*\"([^\"]+)\"");

    @Override
    public Result<LoginVO> wechatMiniappPhoneLogin(String code, String phoneCode) {
        try {
            log.info("[登录服务] 微信小程序手机号快速登录 - code: {}, phoneCode: {}",
                    code != null ? code.substring(0, Math.min(8, code.length())) + "..." : "null",
                    phoneCode != null ? phoneCode.substring(0, Math.min(8, phoneCode.length())) + "..." : "null");
            
            // 1. 通过code获取openid
            String openid = getOpenidByCode(code);
            if (openid == null || openid.isEmpty()) {
                log.warn("[登录服务] 获取openid失败 - code: {}", 
                        code != null ? code.substring(0, Math.min(8, code.length())) + "..." : "null");
                return Result.error(400, "获取用户标识失败，请重试");
            }
            
            // 2. 通过phoneCode获取手机号
            String phoneNumber = getPhoneNumberByCode(phoneCode);
            if (phoneNumber == null || phoneNumber.isEmpty()) {
                log.warn("[登录服务] 获取手机号失败 - phoneCode: {}", 
                        phoneCode != null ? phoneCode.substring(0, Math.min(8, phoneCode.length())) + "..." : "null");
                return Result.error(400, "获取手机号失败，请重试");
            }
            
            log.info("[登录服务] 获取到用户信息 - openid: {}, phone: {}", openid, maskPhone(phoneNumber));
            
            // 3. 查找或创建用户
            User user = userService.getUserByPhone(phoneNumber);
            if (user == null) {
                // 如果手机号不存在，尝试通过openid查找
                user = userService.getUserByOpenId(openid);
            }
            
            if (user == null) {
                // 创建新用户
                user = new User();
                user.setPhone(phoneNumber);
                user.setOpenid(openid);
                user.setNickname("用户" + phoneNumber.substring(7));
                user.setStatus(CommonStatus.ENABLED.getCode());
                user.setCreditScore(100);
                userService.save(user);
                log.info("[登录服务] 创建新用户 - userId: {}, phone: {}, openid: {}", 
                        user.getId(), maskPhone(phoneNumber), openid);
            } else {
                // 更新用户openid（如果是通过手机号找到的用户）
                if (user.getOpenid() == null || !user.getOpenid().equals(openid)) {
                    user.setOpenid(openid);
                    userService.updateById(user);
                    log.info("[登录服务] 更新用户openid - userId: {}", user.getId());
                }
                // 更新用户手机号（如果是通过openid找到的用户）
                if (user.getPhone() == null || !user.getPhone().equals(phoneNumber)) {
                    user.setPhone(phoneNumber);
                    userService.updateById(user);
                    log.info("[登录服务] 更新用户手机号 - userId: {}", user.getId());
                }
            }
            
            // 4. 生成token
            StpUtil.login(user.getId());
            String token = StpUtil.getTokenValue();
            
            log.info("[登录服务] 微信小程序手机号登录成功 - userId: {}, phone: {}", 
                    user.getId(), maskPhone(phoneNumber));
            
            // 5. 构建返回结果
            UserVO userVO = UserVO.builder()
                    .id(user.getId())
                    .phone(user.getPhone())
                    .nickname(user.getNickname())
                    .avatar(user.getAvatar())
                    .build();
            
            LoginVO loginVO = LoginVO.builder()
                    .token(token)
                    .userInfo(userVO)
                    .build();
            
            return Result.success("登录成功", loginVO);
            
        } catch (Exception e) {
            log.error("[登录服务] 微信小程序手机号登录异常", e);
            return Result.error(500, "登录失败：" + e.getMessage());
        }
    }
    
    /**
     * 通过登录凭证code获取openid
     */
    private String getOpenidByCode(String code) {
        try {
            log.info("[微信API] 开始获取openid - appid: {}, code: {}", 
                    miniappAppId, 
                    code != null ? code.substring(0, Math.min(10, code.length())) + "..." : "null");
            
            String url = String.format(
                "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                miniappAppId, miniappSecret, code
            );
            
            log.debug("[微信API] 请求URL: {}", url.replace(miniappSecret, "***"));
            
            // 使用getForObject并手动解析JSON，避免Content-Type问题
            String response = restTemplate.getForObject(url, String.class);
            log.info("[微信API] 获取openid响应 - response: {}", maskSensitiveFields(response));
            
            if (response != null && !response.isEmpty()) {
                // 手动解析JSON
                try {
                    Map<String, Object> result = OBJECT_MAPPER.readValue(response, Map.class);

                    if (result.containsKey("errcode")) {
                        Object errcodeObj = result.get("errcode");
                        int errcode = errcodeObj instanceof Number ? ((Number) errcodeObj).intValue() : -1;
                        if (errcode != 0) {
                            log.error("[微信API] 获取openid失败 - errcode: {}, errmsg: {}", errcode, result.get("errmsg"));
                            return null;
                        }
                    }

                    if (result.containsKey("openid")) {
                        Object openidObj = result.get("openid");
                        String openid = openidObj != null ? openidObj.toString() : null;
                        log.info("[微信API] 获取openid成功 - openid: {}",
                                openid != null ? openid.substring(0, Math.min(10, openid.length())) + "..." : "null");
                        return openid;
                    }
                } catch (Exception parseEx) {
                    log.error("[微信API] 解析响应JSON失败", parseEx);
                }
            }
            
            log.error("[微信API] 获取openid失败 - response: {}", response);
            return null;
        } catch (Exception e) {
            log.error("[微信API] 调用jscode2session异常", e);
            return null;
        }
    }
    
    /**
     * 通过手机号获取凭证code获取手机号
     */
    private String getPhoneNumberByCode(String phoneCode) {
        try {
            // 获取access_token
            String accessToken = getAccessToken();
            if (accessToken == null || accessToken.isEmpty()) {
                log.error("[微信API] 获取access_token失败");
                return null;
            }
            
            // 使用手机号获取凭证换取手机号
            String url = String.format(
                "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s",
                accessToken
            );
            
            // 构建JSON请求体字符串，确保Content-Length正确
            String requestBody = String.format("{\"code\":\"%s\"}", phoneCode);
            
            HttpHeaders headers = new HttpHeaders();
            headers.set("Content-Type", "application/json");
            headers.set("Accept", "application/json");
            headers.setContentLength(requestBody.getBytes(java.nio.charset.StandardCharsets.UTF_8).length);
            
            HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
            
            log.info("[微信API] 请求获取手机号 - phoneCode: {}", 
                    phoneCode != null ? phoneCode.substring(0, Math.min(10, phoneCode.length())) + "..." : "null");
            
            // 使用postForObject并手动解析JSON，避免Content-Type问题
            String response = restTemplate.postForObject(url, entity, String.class);
            log.info("[微信API] 获取手机号响应 - response: {}", maskSensitiveFields(response));
            
            if (response != null && !response.isEmpty()) {
                try {
                    Map<String, Object> result = OBJECT_MAPPER.readValue(response, Map.class);

                    Object errcodeObj = result.get("errcode");
                    int errcode = errcodeObj instanceof Number ? ((Number) errcodeObj).intValue() : -1;
                    if (errcode == 0) {
                        Object phoneInfoObj = result.get("phone_info");
                        if (phoneInfoObj instanceof Map) {
                            @SuppressWarnings("unchecked")
                            Map<String, Object> phoneInfo = (Map<String, Object>) phoneInfoObj;
                            Object phoneObj = phoneInfo.get("phoneNumber");
                            String phoneNumber = phoneObj != null ? phoneObj.toString() : null;
                            log.info("[微信API] 获取手机号成功 - phone: {}",
                                    phoneNumber != null ? phoneNumber.substring(0, 3) + "****" + phoneNumber.substring(7) : "null");
                            return phoneNumber;
                        }
                    } else {
                        log.error("[微信API] 获取手机号失败 - errcode: {}, errmsg: {}",
                                result.get("errcode"), result.get("errmsg"));
                    }
                } catch (Exception parseEx) {
                    log.error("[微信API] 解析响应JSON失败", parseEx);
                }
            }
            
            return null;
        } catch (Exception e) {
            log.error("[微信API] 调用getuserphonenumber异常", e);
            return null;
        }
    }
    
    /**
     * 获取access_token
     */
    private String getAccessToken() {
        try {
            String url = String.format(
                "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
                miniappAppId, miniappSecret
            );
            
            // 使用getForObject并手动解析JSON，避免Content-Type问题
            String response = restTemplate.getForObject(url, String.class);
            log.debug("[微信API] 获取access_token响应 - response: {}", maskSensitiveFields(response));
            
            if (response != null && !response.isEmpty()) {
                try {
                    Map<String, Object> result = OBJECT_MAPPER.readValue(response, Map.class);

                    if (result.containsKey("access_token")) {
                        Object tokenObj = result.get("access_token");
                        String accessToken = tokenObj != null ? tokenObj.toString() : null;
                        log.debug("[微信API] 获取access_token成功");
                        return accessToken;
                    } else {
                        log.error("[微信API] 获取access_token失败 - response: {}", maskSensitiveFields(response));
                    }
                } catch (Exception parseEx) {
                    log.error("[微信API] 解析access_token响应JSON失败", parseEx);
                }
            }
            
            return null;
        } catch (Exception e) {
            log.error("[微信API] 调用获取access_token异常", e);
            return null;
        }
    }
    
    @Override
    public Result<Map<String, Object>> getUserInfo(String userId) {
        try {
            log.debug("[登录服务] 获取用户信息 - userId: {}", userId);
            
            User user = userService.getById(userId);
            if (user == null) {
                log.warn("[登录服务] 用户不存在 - userId: {}", userId);
                return Result.error(404, "用户不存在");
            }
            
            Map<String, Object> userInfo = new HashMap<>();
            userInfo.put("id", user.getId());
            userInfo.put("phone", user.getPhone());
            userInfo.put("nickname", user.getNickname());
            userInfo.put("openid", user.getOpenid());
            
            return Result.success("获取用户信息成功", userInfo);
            
        } catch (Exception e) {
            log.error("[登录服务] 获取用户信息异常 - userId: {}", userId, e);
            return Result.error(500, "获取用户信息失败：" + e.getMessage());
        }
    }
    
    /**
     * 屏蔽微信 API 响应中的敏感字段（session_key、access_token、openid）
     */
    private String maskSensitiveFields(String response) {
        if (response == null) return "null";
        String masked = SESSION_KEY_PATTERN.matcher(response).replaceAll("\"session_key\":\"***\"");
        masked = ACCESS_TOKEN_PATTERN.matcher(masked).replaceAll("\"access_token\":\"***\"");
        masked = OPENID_PATTERN.matcher(masked).replaceAll("\"openid\":\"***\"");
        return masked;
    }

    private String maskPhone(String phone) {
        if (phone == null || phone.length() < 7) {
            return phone;
        }
        return phone.substring(0, 3) + "****" + phone.substring(phone.length() - 4);
    }
}
