package com.cyksj.service.api.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.cyksj.common.constant.Constant;
import com.cyksj.common.exception.BusinessRuntimeException;
import com.cyksj.common.util.Jsons;
import com.cyksj.common.util.StringUtil;
import com.cyksj.model.request.ClaudeCodeApiKeysReq;
import com.cyksj.model.response.claudecode.ClaudeCodeResp;
import com.cyksj.model.views.ClaudeCodeUserApiKeysView;
import com.cyksj.service.api.ClaudeCodexApiService;
import com.github.rholder.retry.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * 项目名: yhlxj11111111
 * 文件名: ClaudeCodexApiServiceImpl
 * 创建者: JavaZou
 * 创建时间:2025/9/25 16:35
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ClaudeCodexApiServiceImpl implements ClaudeCodexApiService {

	@Override
	public ClaudeCodeResp createApiKeys(ClaudeCodeApiKeysReq req) throws Exception {
		String apiKeyUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/keys", req.getUserId());
		Map<String, Object> parmas = new HashMap<>();
		parmas.put("name", req.getName());
		Integer expiresDays = req.getExpiresDays();
		if (expiresDays != null) {
			parmas.put("expires_days", expiresDays);
		}
		ClaudeCodeResp claudeCodeResp = executePostApi(apiKeyUrl, Jsons.toJson(parmas));
		if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
			throw BusinessRuntimeException.getInstance("创建失败");
		}
		return claudeCodeResp;
	}

	@Override
	public void deleteApiKeysById(Long userId, Long keyId) throws Exception {
		String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/keys/%s/%s", userId, keyId);
		HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(Constant.CONNECT_MILLISECONDS).execute();
		String responseBody = execute.body();
		ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
		if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
			log.error("删除key失败：{}", claudeCodeResp.getMessage());
			throw BusinessRuntimeException.getInstance("删除失败");
		}
	}

	@Override
	public List<ClaudeCodeUserApiKeysView> getUserApiKeys(Long codexUserId) {
		String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/keys", codexUserId);
		ClaudeCodeResp claudeCodeResp = executeGetApi(url);
		return Jsons.parseList(claudeCodeResp.getData(), ClaudeCodeUserApiKeysView.class);
	}

	@Override
	public ClaudeCodeResp createOrUpdateCodexUserPackageApi(Long userId, String planName, Integer openaiDailyLimit, Integer openaiQuota, Date expiryTime) throws Exception {
		Map<String, Object> params = new HashMap<>();
		params.put("plan_name", planName.replaceAll(";", ""));
		params.put("openai_daily_limit", openaiDailyLimit);
		params.put("openai_quota", openaiQuota);
		params.put("expire_time", DateUtil.format(expiryTime, "yyyy-MM-dd HH:mm:ss"));
		//claude 类型
		params.put("service_type", "openai");

		String planUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/plan", userId);
		ClaudeCodeResp codexResp = executePostApi(planUrl, Jsons.toJson(params));

		if (!"success".equals(codexResp.getMessage())) {
			log.info("用户codex用户:{}套餐:{}创建或更新失败，info:{}", userId, planName, codexResp.getMessage());
			throw BusinessRuntimeException.getInstance("调用codex 套餐接口失败");
		}

		return codexResp;
	}

	@Override
	public boolean delCodexUserPackages(Long userId) {
		String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/plan?service_type=openai", userId);
		try {
			ClaudeCodeResp claudeCodeResp = executeDeletedApi(url);
			if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
				log.error("删除用户：{} codex套餐失败：{}", userId, claudeCodeResp.getMessage());
				return Boolean.FALSE;
			}
			return Boolean.TRUE;
		} catch (Exception e) {
			log.error("删除用户:{} codex套餐报错：{}", userId, StringUtil.getErrorText(e));
		}
		return Boolean.FALSE;
	}

	@Override
	public ClaudeCodeResp getCodexUserOpenAIUsage(Long userId, String period) {
		// 调用Codex API获取实时使用统计
		String usageUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/usage?period=%s", userId, period);
		ClaudeCodeResp codexResp = executeGetApi(usageUrl);
		return codexResp;
	}

	@Override
	public ClaudeCodeResp getCodexUserDashboard(Long userId) {
		// 调用Codex API获取用户控制台数据
		String dashboardUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/dashboard", userId);
		ClaudeCodeResp codexResp = executeGetApi(dashboardUrl);
		return codexResp;
	}

	@Override
	public ClaudeCodeResp getCodexUserAnalytics(Long userId, String start, String end, Integer page, Integer limit, String order) {
		// 调用Codex API获取用户分析数据
		String analyticsUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/analytics?start=%s&end=%s&page=%s&limit=%s&order=%s", userId, start, end, page, limit, order);
		ClaudeCodeResp codexResp = executeGetApi(analyticsUrl);
		return codexResp;
	}

	/**
	 * GET请求
	 */
	public ClaudeCodeResp executeGetApi(String url) {
		Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
		try {
			return build.call(() -> {
				try {
					HttpResponse execute = HttpUtil.createGet(url)
							.header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY)
							.setConnectionTimeout(Constant.CONNECT_MILLISECONDS)
							.execute();
					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
					if (!Constant.SUCCESS.equals(resp.getMessage())) {
						log.error("GET URL:{}接口返回msg：{}", url, resp.getMessage());
					}
					return resp;
				} catch (HttpException e) {
					return null;
				}
			});
		} catch (ExecutionException | RetryException e) {
			log.error("重试调用GET请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
			throw BusinessRuntimeException.getInstance("接口请求失败");
		}
	}

	/**
	 * Post请求
	 */
	public ClaudeCodeResp executePostApi(String url, String body) {
		Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
		try {
			return build.call(() -> {
				try {
					HttpResponse execute = HttpUtil.createPost(url)
							.header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY)
							.setConnectionTimeout(Constant.CONNECT_MILLISECONDS)
							.body(body)
							.execute();
					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
					if (!Constant.SUCCESS.equals(resp.getMessage())) {
						log.error("POST URL:{}接口返回msg：{}", url, resp.getMessage());
					}
					return resp;
				} catch (Exception e) {
					return null;
				}
			});
		} catch (ExecutionException | RetryException e) {
			log.info("重试调用 POST请求 url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
			throw BusinessRuntimeException.getInstance("接口请求失败");
		}
	}

	/**
	 * claude code DELETE请求
	 */
	public ClaudeCodeResp executeDeletedApi(String url) {
		Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
		try {
			return build.call(() -> {
				try {
					HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(Constant.CONNECT_MILLISECONDS).execute();
					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
					if (!Constant.SUCCESS.equals(resp.getMessage())) {
						log.error("DELETE URL:{}接口返回msg：{}", url, resp.getMessage());
					}
					return resp;
				} catch (HttpException e) {
					return null;
				}
			});
		} catch (ExecutionException | RetryException e) {
			log.error("重试调用DELETE请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
			throw BusinessRuntimeException.getInstance("接口请求失败");
		}
	}

	public Retryer getApiRetryer(Integer sleepSecond, Integer attemptNum) {
		Retryer build = RetryerBuilder.newBuilder()
				.retryIfException()
				//运行时异常重试
				.retryIfRuntimeException()
				//false重试
				.retryIfResult(res -> res == null)
				//1s 间隔
				.withWaitStrategy(WaitStrategies.fixedWait(sleepSecond, TimeUnit.SECONDS))
				//停止策略 : 尝试请求3次
				.withStopStrategy(StopStrategies.stopAfterAttempt(attemptNum)).build();
		return build;
	}
}
