package com.ruoyi.aicall.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.aicall.domain.CcCallPhone;
import com.ruoyi.aicall.service.ICcCallPhoneService;
import com.ruoyi.aicall.service.impl.CcCallPhoneServiceImpl;
import com.ruoyi.cc.domain.CcInboundCdr;
import com.ruoyi.cc.service.ICcInboundCdrService;
import com.ruoyi.cc.service.ICcParamsService;
import com.ruoyi.cc.service.impl.CcInboundCdrServiceImpl;
import com.ruoyi.cc.service.impl.CcParamsServiceImpl;
import com.ruoyi.common.utils.ExceptionUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.web.domain.server.Sys;
import org.apache.poi.hpsf.Decimal;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 计费任务处理队列处理
 */
@Component
public class BillingTaskQueue {

	@Value("${sysconfig.billing.enable:0}")
	private String billingEnable;

	private static  final Logger log = LoggerFactory.getLogger(BillingTaskQueue.class);

	private static ICcParamsService ccParamsService = SpringUtils.getBean(CcParamsServiceImpl.class);
	private static ICcCallPhoneService callPhoneService = SpringUtils.getBean(CcCallPhoneServiceImpl.class);
	private static ICcInboundCdrService inboundCdrService = SpringUtils.getBean(CcInboundCdrServiceImpl.class);

	private static String PARAM_CODE_PRICE_ASR_ALI = "price_aliyun_asr"; // 阿里云asr单价（每小时）
	private static String PARAM_CODE_PRICE_TTS_ALI = "price_aliyun_tts"; // 阿里云tts单价（每千次）
	private static String PARAM_CODE_PRICE_FLOW_TTS_ALI = "price_aliyun_tts_flow"; // 阿里云声音克隆单价（每万字符）
	private static String PARAM_CODE_PRICE_LLM_TOKEN = "price_llm_token"; // 大模型单价（每千token）

	private static final BigDecimal SECONDS_PER_HOUR = BigDecimal.valueOf(3600); // 每小时秒数
	private static final BigDecimal ONE_THOUSAND = BigDecimal.valueOf(1000); // 1000
	private static final BigDecimal TEN_THOUSAND = BigDecimal.valueOf(10000); // 10000


	// 获取单价信息
	// 阿里云asr单价（每小时）
	private static BigDecimal priceAsrAli = new BigDecimal(ccParamsService.getParamValueByCode(PARAM_CODE_PRICE_ASR_ALI, "0.0"));
	// 阿里云tts单价（每千次）
	private static BigDecimal priceTtsAli = new BigDecimal(ccParamsService.getParamValueByCode(PARAM_CODE_PRICE_TTS_ALI, "0.0"));
	// 阿里云声音克隆单价（每万字符）
	private static BigDecimal priceFlowTtsAli = new BigDecimal(ccParamsService.getParamValueByCode(PARAM_CODE_PRICE_FLOW_TTS_ALI, "0.0"));
	// 大模型单价（每千token）
	private static BigDecimal priceLlmAli = new BigDecimal(ccParamsService.getParamValueByCode(PARAM_CODE_PRICE_LLM_TOKEN, "0.0"));


	// 把 static 线程启动块删掉，换成下面方法
	@PostConstruct   // ② 容器初始化完成后执行
	public void init() {
		// 只启动一次后台线程
		if ("1".equals(billingEnable)) {
			new Thread(this::BillingTaskQueue, "billingTaskQueue").start();
		}
	}

	/**
	 * 获取未计费的外呼通话记录和呼入通话记录，根据设置的单价进行计费
	 */
	private void BillingTaskQueue(){

		while(true) {
			try {
				// 获取未计费的cc_call_phone数据
				List<CcCallPhone> callPhoneList = callPhoneService.selectCcCallPhoneList(new CcCallPhone().setBillingStatus(0));
				// 计算每通电话费用
				for (CcCallPhone callPhone: callPhoneList) {
					// 计算token数
					Integer inputTokens = 0; // 总输入token数
					Integer outputTokens = 0; // 总输出token数
					if (StringUtils.isNotEmpty(callPhone.getDialogue())) {
						JSONArray dialogues = JSONArray.parseArray(callPhone.getDialogue());
						for (int i = 0; i < dialogues.size(); i++) {
							JSONObject json = dialogues.getJSONObject(i);
							if ("assistant".equals(json.getString("role"))) {
								if (null != json.getInteger("completionTokens")) {
									outputTokens += json.getInteger("completionTokens");
								}
								if (null != json.getInteger("promptTokens")) {
									inputTokens += json.getInteger("promptTokens");
								}
							}
						}
					}
					callPhone.setInputTokens(inputTokens);
					callPhone.setOutputTokens(outputTokens);
					// 计算总费用
					BigDecimal totalCost = calTotalCost(callPhone.getAsrSeconds(), callPhone.getTtsTimes(), callPhone.getTtsFlowTokens(), callPhone.getInputTokens(), callPhone.getOutputTokens());
					String sql = String.format("update cc_call_phone set total_cost = %s, billing_status = 1 where id = %s;", totalCost.toString(), callPhone.getId());
					ProcessSQLQueue.addSql(sql);
				}
				// 获取未计费的cc_inbound_cdr数据
				List<CcInboundCdr> inboundCdrList = inboundCdrService.selectCcInboundCdrList(new CcInboundCdr().setBillingStatus(0));
				// 计算每通电话费用
				for (CcInboundCdr inboundCdr: inboundCdrList) {
					// 计算token数
					Integer inputTokens = 0; // 总输入token数
					Integer outputTokens = 0; // 总输出token数
					if (StringUtils.isNotEmpty(inboundCdr.getChatContent())) {
						JSONArray dialogues = JSONArray.parseArray(inboundCdr.getChatContent());
						for (int i = 0; i < dialogues.size(); i++) {
							JSONObject json = dialogues.getJSONObject(i);
							if ("assistant".equals(json.getString("role"))) {
								if (null != json.getInteger("completionTokens")) {
									outputTokens += json.getInteger("completionTokens");
								}
								if (null != json.getInteger("promptTokens")) {
									inputTokens += json.getInteger("promptTokens");
								}
							}
						}
					}
					inboundCdr.setInputTokens(inputTokens);
					inboundCdr.setOutputTokens(outputTokens);
					BigDecimal totalCost = calTotalCost(inboundCdr.getAsrSeconds(), inboundCdr.getTtsTimes(), inboundCdr.getTtsFlowTokens(), inboundCdr.getInputTokens(), inboundCdr.getOutputTokens());
					String sql = String.format("update cc_inbound_cdr set total_cost = %s, billing_status = 1 where id = %s;", totalCost.toString(), inboundCdr.getId());
					ProcessSQLQueue.addSql(sql);
				}
			} catch (Exception e) {
				log.error("计费执行异常：{}", ExceptionUtil.getExceptionMessage(e));
			}
			try {
				Thread.sleep(120*1000L); // 每隔2分钟扫描一次
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 *
	 * @param asrSeconds  asr时长（秒）
	 * @param ttsTimes  tts调用次数（次）
	 * @param ttsFlowTokens  大模型tts的字符数（字符）
	 * @param inputTokens  总输入token数
	 * @param outputTokens  总输出token数
	 * @return
	 */
	private static BigDecimal calTotalCost(Integer asrSeconds, Integer ttsTimes, Integer ttsFlowTokens, Integer inputTokens, Integer outputTokens) {
		BigDecimal totalCost = new BigDecimal("0.0");
		// asr费用 = asrSeconds/3600 * priceAsrAli
		if (asrSeconds != null && asrSeconds > 0) {
			totalCost = totalCost.add((BigDecimal.valueOf(asrSeconds).divide(SECONDS_PER_HOUR, 10, RoundingMode.HALF_UP)).multiply(priceAsrAli));
		}
		// tts费用 = ttsTimes / 1000 * priceTtsAli
		if (ttsTimes != null && ttsTimes > 0) {
			totalCost = totalCost.add((BigDecimal.valueOf(ttsTimes).divide(ONE_THOUSAND, 10, RoundingMode.HALF_UP)).multiply(priceTtsAli));
		}
		// cosyvoice费用 = ttsFlowTokens / 10000 * priceFlowTtsAli
		if (ttsFlowTokens != null && ttsFlowTokens > 0) {
			totalCost = totalCost.add((BigDecimal.valueOf(ttsFlowTokens).divide(TEN_THOUSAND, 10, RoundingMode.HALF_UP)).multiply(priceFlowTtsAli));
		}
		// 大模型费用 = (inputTokens + outputTokens) / 1000 * priceLlmAli
		if (inputTokens != null && outputTokens != null && (inputTokens + outputTokens) > 0) {
			totalCost = totalCost.add((BigDecimal.valueOf((inputTokens + outputTokens)).divide(ONE_THOUSAND, 10, RoundingMode.HALF_UP)).multiply(priceLlmAli));
		}
		return totalCost;
	}
}