package com.moka.gdtauto.service;

import java.time.LocalDateTime;
import java.util.UUID;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.moka.gdtauto.config.TencentAdsConfig;
import com.moka.gdtauto.entity.SysUser;
import com.moka.gdtauto.mapper.SysUserMapper;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 系统用户服务
 * 
 * @author moka
 * @since 2026-02-04
 */
@Slf4j
@Service
@AllArgsConstructor
public class SysUserService extends ServiceImpl<SysUserMapper, SysUser> {

    private static final String DEFAULT_PASSWORD = "123456";
    private static final int LOGIN_TOKEN_EXPIRE_DAYS = 7; // 登录令牌有效期：7天
    private static final String CACHE_NAME = "sysUser";

    private final TencentAdsConfig tencentAdsConfig;
    /**
     * 生成登录令牌
     * 
     * @return 登录令牌
     */
    private String generateLoginToken() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 更新用户登录令牌
     * 
     * @param user 用户信息
     */
    @CacheEvict(value = CACHE_NAME, key = "#user.jobNumber")
    private void updateLoginToken(SysUser user) {
        String loginToken = generateLoginToken();
        LocalDateTime expiresAt = LocalDateTime.now().plusDays(LOGIN_TOKEN_EXPIRE_DAYS);
        
        user.setLoginToken(loginToken);
        user.setLoginTokenExpiresAt(expiresAt);
        updateById(user);
        
        log.info("更新用户登录令牌，工号={}，过期时间={}", user.getJobNumber(), expiresAt);
    }

    /**
     * 根据手机号查询用户
     * 
      * @param jobNumber 工号
     * @return 用户信息
     */
    @Cacheable(value = CACHE_NAME, key = "#jobNumber", unless = "#result == null")
    public SysUser getByJobNumber(String jobNumber) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getJobNumber, jobNumber)
                .eq(SysUser::getDeleted, 0)
                .last("LIMIT 1");
        return getOne(wrapper);
    }

    /**
     * 用户登录验证
     * 
     * @param jobNumber 工号
     * @param password 密码（明文）
     * @return 用户信息，验证失败返回null
     */
    public SysUser login(String jobNumber, String password) {
        SysUser user = getByJobNumber(jobNumber);
        if (user == null) {
            log.warn("用户登录失败：用户不存在，工号={}", jobNumber);
            return null;
        }
        
        if (user.getStatus() == 0) {
            log.warn("用户登录失败：账号已禁用，工号={}", jobNumber);
            return null;
        }
        
        // 密码加密：password + '#' + jobNumber 的MD5
        String encryptedPassword = password + "#" + jobNumber;
        encryptedPassword = DigestUtils.md5DigestAsHex(encryptedPassword.getBytes());
        
        if (!encryptedPassword.equals(user.getPassword())) {
            log.warn("用户登录失败：密码错误，工号={}", jobNumber);
            return null;
        }
        
        // 登录成功，更新登录令牌
        updateLoginToken(user);
        
        log.info("用户登录成功，工号={}", jobNumber);
        return user;
    }

    /**
     * 根据登录令牌查询用户
     * 
     * @param loginToken 登录令牌
     * @return 用户信息，令牌无效或过期返回null
     */
    public SysUser getByLoginToken(String loginToken) {
        if (loginToken == null || loginToken.isEmpty()) {
            return null;
        }
        
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getLoginToken, loginToken)
                .eq(SysUser::getDeleted, 0)
                .eq(SysUser::getStatus, 1)
                .last("LIMIT 1");
        
        SysUser user = getOne(wrapper);
        
        // 检查令牌是否过期
        if (user != null && user.getLoginTokenExpiresAt() != null) {
            if (user.getLoginTokenExpiresAt().isBefore(LocalDateTime.now())) {
                log.warn("登录令牌已过期，工号={}", user.getJobNumber());
                return null;
            }
        }
        
        return user;
    }
    
    /**
     * 获取实名认证令牌授权URL
     * 
     * @param redirectUri 认证完成后的回调地址
     * @param state 自定义参数
     * @return 实名认证授权URL
     */
    public String getUserTokenUrl(String state) {
        try {
            String encodedRedirectUri = java.net.URLEncoder.encode(tencentAdsConfig.getUserTokenRedirectUri(), "UTF-8");
            String encodedState = state != null && !state.isEmpty() 
                ? java.net.URLEncoder.encode(state, "UTF-8") 
                : "";
            
            String baseUrl = "https://ad.qq.com/account-center/single/user-authorize";
            if (encodedState.isEmpty()) {
                return String.format("%s?redirect_uri=%s", baseUrl, encodedRedirectUri);
            } else {
                return String.format("%s?redirect_uri=%s&state=%s", 
                    baseUrl, encodedRedirectUri, encodedState);
            }
        } catch (Exception e) {
            log.error("生成实名认证URL失败", e);
            throw new RuntimeException("生成实名认证URL失败：" + e.getMessage());
        }
    }

    /**
     * 保存实名认证令牌
     * 通过手机号直接保存
     * 
     * @param jobNumber 工号（从state参数解析）
     * @param userStatus 用户认证状态: 0-未找到账号, 1-未完成实名认证, 2-已完成实名认证
     * @param userToken 实名认证令牌
     * @param expireTime 令牌过期时间戳（秒）
     * @return 用户信息
     * @throws Exception 处理异常
     */
    @Transactional(rollbackFor = Exception.class)
    public SysUser saveUserToken(String jobNumber, Integer userStatus, 
                                 String userToken, Long expireTime) throws Exception {
        // 校验手机号
        if (jobNumber == null || jobNumber.isEmpty()) {
            throw new Exception("工号不能为空");
        }
        
        if (userStatus == null) {
            throw new Exception("用户认证状态不能为空");
        }
        
        if (userStatus == 0) {
            throw new Exception("未找到腾讯广告员工账号，请先在服务商系统或客户工作台注册");
        }
        
        if (userStatus == 1) {
            throw new Exception("账号未完成实名认证，请先在服务商系统或客户工作台完成实名认证+组织认证");
        }
        
        // userStatus == 2 表示已完成实名认证
        if (userToken == null || userToken.isEmpty()) {
            throw new Exception("实名认证令牌不能为空");
        }
        
        if (expireTime == null) {
            throw new Exception("令牌过期时间不能为空");
        }
        
        try {
            // URL解码user_token
            String decodedUserToken = java.net.URLDecoder.decode(userToken, "UTF-8");
            
            // 转换过期时间
            LocalDateTime expiresAt = LocalDateTime.ofInstant(
                java.time.Instant.ofEpochSecond(expireTime),
                java.time.ZoneId.systemDefault()
            );
            
            // 保存到用户表
            SysUser user = this.saveOrUpdateUserToken(
                jobNumber, decodedUserToken, expiresAt, userStatus
            );
            
            log.info("保存实名认证令牌成功，jobNumber={}，过期时间={}", jobNumber, expiresAt);
            
            return user;
            
        } catch (Exception e) {
            log.error("保存实名认证令牌失败", e);
            throw new Exception("保存实名认证令牌失败：" + e.getMessage());
        }
    }

    /**
     * 保存或更新用户令牌
     * 
     * @param phone 手机号
     * @param userToken 实名认证令牌
     * @param expiresAt 过期时间
     * @param userStatus 认证状态
     * @return 用户信息
     */
    @Transactional(rollbackFor = Exception.class)
    public SysUser saveOrUpdateUserToken(String jobNumber, String userToken, 
                                         LocalDateTime expiresAt, Integer userStatus) {
        SysUser user = getByJobNumber(jobNumber);
        
        if (user == null) {
            user = new SysUser();
            user.setJobNumber(jobNumber);
            // password + '#' +  jobNumber md5
            String password = DEFAULT_PASSWORD + "#" + jobNumber;
            password = DigestUtils.md5DigestAsHex(password.getBytes());
            user.setPassword(password);
            user.setDefaultPwd(1);
            user.setStatus(1);
        }
        
        user.setUserToken(userToken);
        user.setUserTokenExpiresAt(expiresAt);
        user.setUserStatus(userStatus);
        
        saveOrUpdate(user);
        
        log.info("保存用户令牌，jobNumber={}，过期时间={}", jobNumber, expiresAt);
        
        return user;
    }

    /***
     * 修改密码
     * @param jobNumber
     * @param newPassword
     * @return
     */

    public boolean changePassword(String jobNumber, String newPassword) {
        SysUser user = getByJobNumber(jobNumber);
        if (user == null) {
            return false;
        }
        String password = newPassword + "#" + jobNumber;
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        user.setPassword(password);
        user.setDefaultPwd(0);
        updateById(user);
        return true;
    }

    /**
     * 检查用户令牌是否有效
     * 
     * @param user 用户信息
     * @return 是否有效
     */
    public boolean isUserTokenValid(SysUser user) {
        if (user == null || user.getStatus() == 0) {
            return false;
        }
        
        if (user.getUserStatus() == null || user.getUserStatus() != 2) {
            return false;
        }
        
        if (user.getUserToken() == null || user.getUserToken().isEmpty()) {
            return false;
        }
        
        if (user.getUserTokenExpiresAt() == null) {
            return false;
        }
        
        LocalDateTime now = LocalDateTime.now();
        return user.getUserTokenExpiresAt().isAfter(now);
    }
}
