package com.cyksj.server.recharge.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cyksj.common.constant.Constant;
import com.cyksj.common.exception.BusinessRuntimeException;
import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
import com.cyksj.mapper.*;
import com.cyksj.model.entity.*;
import com.cyksj.model.request.GroupsRelationRechargeReq;
import com.cyksj.redis.RedisService;
import com.cyksj.server.recharge.GptProxyRechargeService;
import com.cyksj.server.recharge.dto.CardKeyValidationResult;
import com.cyksj.server.recharge.dto.TaskResult;
import com.cyksj.server.recharge.dto.TaskSubmitResult;
import com.cyksj.server.recharge.dto.TokenParseResult;
import com.cyksj.service.chatgpt.GptUserRechargeRecordService;
import com.cyksj.service.user.UserBindRelationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * @author chan
 * @date 2025/7/30 18:55
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GptProxyRechargeServiceImpl implements GptProxyRechargeService {

    private static final String BASE_URL = "https://api.ow521.com/api";

    private final GptRechargeCardKeyMapper gptRechargeCardKeyMapper;

    private final GroupsRelationMapper relationMapper;

    private final UserBindRelationService userBindRelationService;

    private final GroupsMapper groupsMapper;

    private final GoodsDonSkuMapper skuMapper;

    private final OrderDonMapper orderDonMapper;

	private final GptUserRechargeRecordService gptUserRechargeRecordService;

	private final RedisService redisService;

	private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();

	private HttpRequest createBaseRequest(String uri) {
        return HttpRequest.get(BASE_URL + uri)
                .header("accept", "application/json, text/plain, */*")
                .header("accept-language", "zh-CN,zh;q=0.9,en;q=0.8")
                .header("origin", "https://www.ow520.com")
                .header("referer", "https://www.ow520.com/")
                .header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36");
    }

    public CardKeyValidationResult validateCardKey(String cardKey) {
        log.info("开始验证卡密: {}", cardKey);
        try {
            HttpResponse response = createBaseRequest("/card-keys/" + cardKey)
                    .execute();
            String body = response.body();
            log.info("卡密验证响应: {}", body);
            
            JSONObject jsonResponse = JSONUtil.parseObj(body);
            CardKeyValidationResult result = new CardKeyValidationResult(
                jsonResponse.getBool("available")
            );
            //{"available":false,"error":"卡密已被使用"}
            log.info("卡密验证结果: {}", result);
            return result;
        } catch (Exception e) {
            log.error("验证卡密失败: {}", e.getMessage(), e);
            throw new RuntimeException("验证卡密失败: " + e.getMessage(), e);
        }
    }

    public TokenParseResult parseToken(String accessToken) {
        log.info("开始验证凭证: {}", accessToken.substring(0, Math.min(20, accessToken.length())) + "...");
        try {
            String url = BASE_URL + "/parse-token";
            JSONObject requestBody = new JSONObject();
            requestBody.put("access_token", accessToken);
            
            HttpResponse response = HttpRequest.post(url)
                    .header("accept", "application/json, text/plain, */*")
                    .header("accept-language", "zh-CN,zh;q=0.9,en;q=0.8")
                    .header("content-type", "application/json")
                    .header("origin", "https://www.ow520.com")
                    .header("referer", "https://www.ow520.com/")
                    .header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36")
                    .body(requestBody.toString())
                    .execute();
            String body = response.body();
            log.info("凭证验证响应: {}", body);
            
            JSONObject jsonResponse = JSONUtil.parseObj(body);
            TokenParseResult result = new TokenParseResult(
                jsonResponse.getStr("message"),
                jsonResponse.getBool("success")
            );
            log.info("凭证验证结果: {}", result);
            return result;
        } catch (Exception e) {
            log.error("验证凭证失败: {}", e.getMessage(), e);
            throw new RuntimeException("验证凭证失败: " + e.getMessage(), e);
        }
    }

    public TaskSubmitResult submitTask(String cardKey, String accessToken, String idp) {
        log.info("开始提交任务 - 卡密: {}, idp: {}", cardKey, idp);
        try {
            String url = BASE_URL + "/tasks";
            JSONObject requestBody = new JSONObject();
            requestBody.put("card_key", cardKey);
            requestBody.put("access_token", accessToken);
            requestBody.put("idp", idp);
            
            HttpResponse response = HttpRequest.post(url)
		            .setConnectionTimeout(60000)
		            .header("accept", "application/json, text/plain, */*")
                    .header("accept-language", "zh-CN,zh;q=0.9,en;q=0.8")
                    .header("content-type", "application/json")
                    .header("origin", "https://www.ow520.com")
                    .header("referer", "https://www.ow520.com/")
                    .header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36")
                    .body(requestBody.toString())
                    .execute();
            String body = response.body();
            log.info("任务提交响应: {}", body);
            
            JSONObject jsonResponse = JSONUtil.parseObj(body);
            TaskSubmitResult result = new TaskSubmitResult(
                jsonResponse.getStr("task_id"),
                jsonResponse.getBool("success")
            );
            log.info("任务提交结果: {}", result);
            return result;
        } catch (Exception e) {
            log.error("提交任务失败: {}", e.getMessage(), e);
            throw new RuntimeException("提交任务失败: " + e.getMessage(), e);
        }
    }

    public TaskResult getTaskResult(String taskId) {
        log.info("开始查询任务结果: {}", taskId);
        try {
            String uri = "/tasks/" + taskId;
            HttpResponse response = createBaseRequest(uri)
                    .execute();
            String body = response.body();
            log.info("任务查询响应: {}", body);

            JSONObject jsonResponse = JSONUtil.parseObj(body);
            TaskResult result = new TaskResult(
                jsonResponse.getStr("status"),
                jsonResponse.getStr("result"),
                jsonResponse.getStr("error")
            );
            log.info("任务查询结果: {}", result);
	        String status = result.getStatus();
	        String resultResult = Optional.ofNullable(result.getError()).orElse(result.getResult());
			//更新代充状态
			resetGroupsRelationRechargeStatus(taskId, status, resultResult);
	        return result;
        } catch (Exception e) {
            log.error("获取任务结果失败: {}", e.getMessage(), e);
            throw new RuntimeException("获取任务结果失败: " + e.getMessage(), e);
        }
    }

	@Override
	@Transactional(rollbackFor = Throwable.class)
	public String confirmRecharge(GroupsRelationRechargeReq req) {
		Long relationId = req.getRelationId();
		Long userId = req.getUserId();
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		GroupsRelation relation = relationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
				.in(GroupsRelation::getUserId, userIdList)
				.eq(GroupsRelation::getId, relationId)
				.eq(GroupsRelation::getStatus, GroupsRelation.Status.validity));
		if (relation == null) {
			throw BusinessRuntimeException.getInstance("车票不存在");
		}
		String userAccount = relation.getAccount();
		GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId());
		GoodsDonSku sku = skuMapper.selectById(groupsTrips.getSkuId());
//		//GPT 代充
//		if (sku.getGoodsId() != Constant.GPT_RECHARGE_GOODS_ID) {
//			throw BusinessRuntimeException.getInstance("车票类型错误");
//		}
		Integer rechargeRemainNum = relation.getRechargeRemainNum();
		if (rechargeRemainNum == null || rechargeRemainNum <= 0) {
			throw BusinessRuntimeException.getInstance("剩余可代充次数为0");
		}
		if (relation.getRechargeStatus() == GroupsRelation.RechargeStatus.recharging) {
			throw BusinessRuntimeException.getInstance("确认充值中");
		}
		if (relation.getRechargeStatus() == GroupsRelation.RechargeStatus.recharge_error) {
			throw BusinessRuntimeException.getInstance("充值失败，请联系客服开通");
		}
		String key = RedisService.key.GPT_RECHARGE_KEY.getName() + relationId;
		boolean b = redisService.setNx(key, relationId, RedisService.key.GPT_RECHARGE_KEY.getTimeout());
		if (!b) {
			throw BusinessRuntimeException.getInstance("确认充值中");
		}
		try {
			int updateRemainNum = relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
					.set(GroupsRelation::getRechargeRemainNum, rechargeRemainNum - 1)
					.eq(GroupsRelation::getId, relationId)
					.eq(GroupsRelation::getUserId, relation.getUserId())
					.eq(GroupsRelation::getRechargeRemainNum, rechargeRemainNum));
			if (updateRemainNum == 0) {
				throw BusinessRuntimeException.getInstance("代充异常，请重试");
			}
			OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
					.in(OrderDon::getUserId, userIdList)
					.eq(OrderDon::getRelationId, relationId)
					.notIn(OrderDon::getStatus, Constant.noOrderAllStatus)
					.orderByDesc(OrderDon::getId)
					.last("limit 1"));
			if (orderDon == null) {
				throw BusinessRuntimeException.getInstance("代充订单不存在或已退款");
			}
			String accessToken = req.getAccessToken();
			//验证用户token是否正确
			TokenParseResult tokenParseResult = parseToken(accessToken);
			if (!tokenParseResult.getSuccess()) {
				throw BusinessRuntimeException.getInstance("您输入的凭证有误，请重新输入");
			}
			String rechargeAccount = tokenParseResult.getMessage();
			//月付校验前后账号是否一致
			if (sku.getMonths() == 1 && !StrUtil.equals(rechargeAccount, userAccount)) {
				throw BusinessRuntimeException.getInstance("请填入绑定账号的token");
			}
			//记录代充账号 token
			relation.setGptToken(accessToken);
			relation.setAccount(rechargeAccount);
			//获取GPT代充key
			GptRechargeCardKey gptRechargeCardKey = gptRechargeCardKeyMapper.selectOne(Wrappers.lambdaQuery(GptRechargeCardKey.class)
					.eq(GptRechargeCardKey::getStatus, Boolean.FALSE)
					.last("order by rand() limit 1"));
			if (gptRechargeCardKey == null) {
				setRechargeRelationStatusAutoError(relation);
				throw BusinessRuntimeException.getInstance("充值失败，请联系客服开通");
			}
			int update = gptRechargeCardKeyMapper.update(null, Wrappers.lambdaUpdate(GptRechargeCardKey.class)
					.set(GptRechargeCardKey::getStatus, Boolean.TRUE)
					.set(GptRechargeCardKey::getOrderId, orderDon.getId())
					.set(GptRechargeCardKey::getOrderNo, orderDon.getOrderNo())
					.eq(GptRechargeCardKey::getId, gptRechargeCardKey.getId())
					.eq(GptRechargeCardKey::getStatus, Boolean.FALSE));
			if (update == 0) {
				setRechargeRelationStatusAutoError(relation);
				throw BusinessRuntimeException.getInstance("充值失败，请联系客服开通");
			}
			String gptCardKey = gptRechargeCardKey.getCardKey();
			//校验卡密是否可用
			CardKeyValidationResult cardKeyValidationResult = validateCardKey(gptCardKey);
			if (!cardKeyValidationResult.getAvailable()) {
				setRechargeRelationStatusAutoError(relation);
				throw BusinessRuntimeException.getInstance("充值失败，请联系客服开通");
			}
			//提交任务
			TaskSubmitResult result = submitTask(gptCardKey, accessToken, "auth0");
			if (!result.getSuccess()) {
				setRechargeRelationStatusAutoError(relation);
				throw BusinessRuntimeException.getInstance("充值失败，请联系客服开通");
			}
			String taskId = result.getTaskId();
			relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
					//记录代充账号
					.set(GroupsRelation::getAccount, rechargeAccount)
					.set(GroupsRelation::getRechargeStatus, GroupsRelation.RechargeStatus.recharging)
					.set(GroupsRelation::getCardKey, gptCardKey)
					.set(GroupsRelation::getGptToken, accessToken)
					.set(GroupsRelation::getGptTaskId, taskId)
					.eq(GroupsRelation::getId, relationId));
			return taskId;
		} finally {
			if (redisService.hasKey(key)) {
				redisService.del(key);
			}
		}
	}

	/**
	 * 设置代充自动充值异常
	 */
	public void setRechargeRelationStatusAutoError(GroupsRelation relation) {
		TASK_EXECUTOR.execute(()->{
			relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
					.set(GroupsRelation::getAccount, relation.getAccount())
					.set(GroupsRelation::getGptToken, relation.getGptToken())
					.set(GroupsRelation::getRechargeStatus, GroupsRelation.RechargeStatus.recharge_error)
					.eq(GroupsRelation::getId, relation.getId()));
		});
	}

	/**
	 * 更新代充状态
	 */
	private void resetGroupsRelationRechargeStatus(String taskId, String status, String result) {
		if ("completed".equals(status) || "failed".equals(status) || "unknown".equals(status)) {
			GroupsRelation relation = relationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
					.eq(GroupsRelation::getGptTaskId, taskId)
					.last("limit 1"));
			if (relation != null && relation.getRechargeStatus() == GroupsRelation.RechargeStatus.recharging) {
				Integer rechargeRemainNum = relation.getRechargeRemainNum();
				GroupsRelation.RechargeStatus rechargeStatus = "completed".equals(status) ? GroupsRelation.RechargeStatus.complete : GroupsRelation.RechargeStatus.recharge_error;
				String cardKey = relation.getCardKey();
				GptRechargeCardKey gptRechargeCardKey = gptRechargeCardKeyMapper.selectOne(Wrappers.lambdaQuery(GptRechargeCardKey.class)
						.eq(GptRechargeCardKey::getCardKey, cardKey)
						.last("limit 1"));
				if (rechargeStatus == GroupsRelation.RechargeStatus.recharge_error) {
					if (gptRechargeCardKey != null) {
						gptRechargeCardKeyMapper.update(null, Wrappers.lambdaUpdate(GptRechargeCardKey.class)
								.set(GptRechargeCardKey::getStatus, Boolean.FALSE)
								.set(GptRechargeCardKey::getOrderId, null)
								.set(GptRechargeCardKey::getOrderNo, null)
								.eq(GptRechargeCardKey::getId, gptRechargeCardKey.getId())
								.eq(GptRechargeCardKey::getStatus, Boolean.TRUE));
					}
				}
				if (rechargeStatus == GroupsRelation.RechargeStatus.recharge_error) {
					if (!redisService.setNx(RedisService.key.GPT_RECHARGE_RECOVER_KEY.getName() + taskId, taskId, RedisService.key.GPT_RECHARGE_RECOVER_KEY.getTimeout())) {
						return;
					}
				}
				Date startTime = relation.getStartTime();
				DateTime expiryTime = null;
				if (rechargeStatus == GroupsRelation.RechargeStatus.complete && startTime == null) {
					GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId());
					if (groupsTrips != null) {
						startTime = DateTime.now();
						GoodsDonSku sku = skuMapper.selectById(groupsTrips.getSkuId());
						if (sku.getDays() != null && sku.getDays() > 0) {
							expiryTime = DateUtil.offsetDay(startTime, sku.getDays());
						} else {
							expiryTime = DateUtil.offsetMonth(startTime, sku.getMonths());
						}
					}
				}
				String rechargeErrorInfo = null;
				if (rechargeStatus == GroupsRelation.RechargeStatus.recharge_error) {
					rechargeErrorInfo = result;
				}
				relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
						.set(rechargeStatus == GroupsRelation.RechargeStatus.recharge_error, GroupsRelation::getRechargeRemainNum, rechargeRemainNum + 1)
						.set(GroupsRelation::getRechargeStatus, rechargeStatus)
						.set(expiryTime != null, GroupsRelation::getStartTime, startTime)
						.set(expiryTime != null, GroupsRelation::getExpiryTime, expiryTime)
						.set(StrUtil.isNotEmpty(rechargeErrorInfo), GroupsRelation::getRechargeErrorInfo, rechargeErrorInfo)
						.eq(GroupsRelation::getId, relation.getId())
						.le(GroupsRelation::getRechargeRemainNum, relation.getRechargeNum())
						.eq(GroupsRelation::getRechargeStatus, GroupsRelation.RechargeStatus.recharging));
				//记录代充记录
				if (rechargeStatus == GroupsRelation.RechargeStatus.complete) {
					gptUserRechargeRecordService.recordGptUserRechargeNum(relation.getUserId(), relation.getId(), relation.getAccount(), -1, null, "自动代充");
					//修改对应订单状态
					if (gptRechargeCardKey != null) {
						Long orderId = gptRechargeCardKey.getOrderId();
						OrderDon orderDon = orderDonMapper.selectById(orderId);
						if (orderDon != null && orderDon.getStatus() == OrderDon.Status.hasPayment) {
							orderDon.setStatus(OrderDon.Status.complete);
							orderDonMapper.updateById(orderDon);
						}
					}
				}
			}
		}
	}
}
