package com.chinaweal.aiccs.org.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chinaweal.aiccs.common.util.StringUtils;
import com.chinaweal.aiccs.org.entity.OauthAuthorizationCode;
import com.chinaweal.aiccs.org.entity.dto.AuthorizationRequestDTO;
import com.chinaweal.aiccs.org.mapper.OauthAuthorizationCodeMapper;
import com.chinaweal.aiccs.org.service.IOauthAuthorizationCodeService;
import com.chinaweal.youfool.framework.springboot.exception.custom.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Random;

/**
 * OAuth授权码服务实现
 *
 * @author chinaweal
 * @since 2025-11-21
 */
@Slf4j
@Service
public class OauthAuthorizationCodeServiceImpl extends ServiceImpl<OauthAuthorizationCodeMapper, OauthAuthorizationCode>
        implements IOauthAuthorizationCodeService {

    /**
     * 授权码有效期（分钟）
     */
    private static final int AUTHORIZATION_CODE_EXPIRE_MINUTES = 10;

    /**
     * 授权码长度
     */
    private static final int AUTHORIZATION_CODE_LENGTH = 43;

    /**
     * 授权码字符集
     */
    private static final String AUTH_CODE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";

    private final Random random = new Random();

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createAuthorizationCode(AuthorizationRequestDTO authorizationRequest, String userId, String userName) {
        log.info("开始创建授权码，客户端ID: {}, 用户ID: {}", authorizationRequest.getClientId(), userId);

        try {
            // 生成授权码
            String authorizationCode = generateAuthorizationCode();

            // 计算过期时间
            LocalDateTime expiresAt = LocalDateTime.now().plusMinutes(AUTHORIZATION_CODE_EXPIRE_MINUTES);

            // 创建授权码实体
            OauthAuthorizationCode oauthAuthorizationCode = new OauthAuthorizationCode()
                    .setCodeId(StringUtils.getUUID())
                    .setAuthorizationCode(authorizationCode)
                    .setClientId(authorizationRequest.getClientId())
                    .setUserId(userId)
                    .setUserName(userName)
                    .setScope(authorizationRequest.getScope())
                    .setRedirectUri(authorizationRequest.getRedirectUri())
                    .setState(authorizationRequest.getState())
                    .setGrantType("authorization_code")
                    .setExpiresAt(expiresAt)
                    .setIsUsed("0")
                    .setIsActive("1");

            // 保存到数据库
            boolean saved = save(oauthAuthorizationCode);
            if (!saved) {
                throw new BusinessException("保存授权码失败");
            }

            log.info("授权码创建成功，授权码: {}, 过期时间: {}", authorizationCode, expiresAt);
            return authorizationCode;

        } catch (Exception e) {
            log.error("创建授权码失败，客户端ID: {}, 用户ID: {}", authorizationRequest.getClientId(), userId, e);
            throw new BusinessException("创建授权码失败: " + e.getMessage());
        }
    }

    @Override
    public OauthAuthorizationCode validateAuthorizationCode(String code, String clientId) {
        log.info("开始验证授权码，授权码: {}, 客户端ID: {}", code, clientId);

        if (StringUtils.isBlank(code)) {
            log.warn("授权码为空");
            return null;
        }

        if (StringUtils.isBlank(clientId)) {
            log.warn("客户端ID为空，授权码: {}", code);
            return null;
        }

        try {
            // 根据授权码和客户端ID查询
            OauthAuthorizationCode authorizationCode = baseMapper.selectByCodeAndClientId(code, clientId);

            if (authorizationCode == null) {
                log.warn("未找到授权码信息，授权码: {}, 客户端ID: {}", code, clientId);
                return null;
            }

            // 检查是否已使用
            if ("1".equals(authorizationCode.getIsUsed())) {
                log.warn("授权码已被使用，授权码: {}, 客户端ID: {}", code, clientId);
                return null;
            }

            // 检查是否有效
            if ("0".equals(authorizationCode.getIsActive())) {
                log.warn("授权码已无效，授权码: {}, 客户端ID: {}", code, clientId);
                return null;
            }

            // 检查是否过期
            if (authorizationCode.getExpiresAt().isBefore(LocalDateTime.now())) {
                log.warn("授权码已过期，授权码: {}, 过期时间: {}, 当前时间: {}",
                        code, authorizationCode.getExpiresAt(), LocalDateTime.now());
                // 自动标记为无效
                markCodeAsInvalid(code);
                return null;
            }

            log.info("授权码验证成功，授权码: {}, 客户端ID: {}", code, clientId);
            return authorizationCode;

        } catch (Exception e) {
            log.error("验证授权码失败，授权码: {}, 客户端ID: {}", code, clientId, e);
            return null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean consumeAuthorizationCode(String code, String clientId) {
        log.info("开始使用授权码，授权码: {}", code);

        if (StringUtils.isBlank(code)) {
            log.warn("授权码为空");
            return false;
        }

        try {
            // 标记为已使用
            int updated = baseMapper.markAsUsed(code, clientId);

            if (updated > 0) {
                log.info("授权码使用成功，授权码: {}", code);
                return true;
            } else {
                log.warn("授权码使用失败，未找到记录或已被使用，授权码: {}", code);
                return false;
            }

        } catch (Exception e) {
            log.error("使用授权码失败，授权码: {}", code, e);
            return false;
        }
    }

    @Override
    public boolean isAuthorizationCodeValid(String code) {
        log.info("检查授权码是否有效，授权码: {}", code);

        if (StringUtils.isBlank(code)) {
            return false;
        }

        try {
            OauthAuthorizationCode authorizationCode = getAuthorizationCode(code);

            if (authorizationCode == null) {
                return false;
            }

            // 检查是否已使用
            if ("1".equals(authorizationCode.getIsUsed())) {
                return false;
            }

            // 检查是否有效
            if ("0".equals(authorizationCode.getIsActive())) {
                return false;
            }

            // 检查是否过期
            if (authorizationCode.getExpiresAt().isBefore(LocalDateTime.now())) {
                // 自动标记为无效
                markCodeAsInvalid(code);
                return false;
            }

            return true;

        } catch (Exception e) {
            log.error("检查授权码有效性失败，授权码: {}", code, e);
            return false;
        }
    }

    @Override
    public OauthAuthorizationCode getAuthorizationCode(String code) {
        log.info("获取授权码信息，授权码: {}", code);

        if (StringUtils.isBlank(code)) {
            return null;
        }

        try {
            OauthAuthorizationCode authorizationCode = baseMapper.selectByAuthorizationCode(code);

            if (authorizationCode != null) {
                log.info("获取授权码信息成功，授权码: {}, 客户端ID: {}",
                        code, authorizationCode.getClientId());
            } else {
                log.warn("未找到授权码信息，授权码: {}", code);
            }

            return authorizationCode;

        } catch (Exception e) {
            log.error("获取授权码信息失败，授权码: {}", code, e);
            return null;
        }
    }

    /**
     * 生成授权码
     *
     * @return 授权码
     */
    private String generateAuthorizationCode() {
        StringBuilder sb = new StringBuilder(AUTHORIZATION_CODE_LENGTH);
        for (int i = 0; i < AUTHORIZATION_CODE_LENGTH; i++) {
            sb.append(AUTH_CODE_CHARS.charAt(random.nextInt(AUTH_CODE_CHARS.length())));
        }
        return sb.toString();
    }

    /**
     * 标记授权码为无效
     *
     * @param code 授权码
     */
    private void markCodeAsInvalid(String code) {
        try {
            QueryWrapper<OauthAuthorizationCode> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("authorization_code", code);
            queryWrapper.eq("is_active", "1");

            OauthAuthorizationCode updateEntity = new OauthAuthorizationCode();
            updateEntity.setIsActive("0");
            updateEntity.setUpdateTime(LocalDateTime.now());

            update(updateEntity, queryWrapper);
            log.info("授权码标记为无效成功，授权码: {}", code);
        } catch (Exception e) {
            log.error("标记授权码为无效失败，授权码: {}", code, e);
        }
    }

    /**
     * 清理过期的授权码
     * 这个方法可以定期调用，例如通过定时任务
     */
    @Transactional(rollbackFor = Exception.class)
    public void cleanExpiredAuthorizationCodes() {
        log.info("开始清理过期的授权码");

        try {
            int updated = baseMapper.markExpiredAsInactive();
            log.info("过期的授权码清理完成，更新记录数: {}", updated);
        } catch (Exception e) {
            log.error("清理过期授权码失败", e);
            throw new BusinessException("清理过期授权码失败: " + e.getMessage());
        }
    }
}