package com.tzld.piaoquan.api.job;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.odps.data.Record;
import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.tzld.piaoquan.api.component.AdApiService;
import com.tzld.piaoquan.api.component.AigcApiService;
import com.tzld.piaoquan.api.component.DeepSeekApiService;
import com.tzld.piaoquan.api.dao.mapper.GhDetailMapperExt;
import com.tzld.piaoquan.api.dao.mapper.GzhAutoreplyBehaviorUvTotalMapper;
import com.tzld.piaoquan.api.model.bo.AdPutCreativeComponentCostData;
import com.tzld.piaoquan.api.model.bo.GoogleLLMResult;
import com.tzld.piaoquan.api.model.bo.VideoDetail;
import com.tzld.piaoquan.api.model.dto.AIResult;
import com.tzld.piaoquan.api.model.po.GzhAutoreplyBehaviorUvTotal;
import com.tzld.piaoquan.api.model.po.GzhAutoreplyBehaviorUvTotalExample;
import com.tzld.piaoquan.api.model.vo.GhDetailVo;
import com.tzld.piaoquan.api.service.GhDetailService;
import com.tzld.piaoquan.api.util.AliOssFileTool;
import com.tzld.piaoquan.api.util.CdnUtil;
import com.tzld.piaoquan.growth.common.model.po.GhDetail;
import com.tzld.piaoquan.growth.common.utils.DateUtil;
import com.tzld.piaoquan.growth.common.utils.OdpsUtil;
import com.tzld.piaoquan.growth.common.utils.TitleSimilarCheckUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class GzhReplyVideoRefreshJob {

    @Autowired
    GhDetailService ghDetailService;
    @Autowired
    AdApiService adApiService;
    @Autowired
    AigcApiService aigcApiService;
    @Autowired
    DeepSeekApiService deepSeekApiService;
    @Autowired
    GhDetailMapperExt ghDetailMapperExt;
    @Autowired
    GzhAutoreplyBehaviorUvTotalMapper gzhAutoreplyBehaviorUvTotalMapper;

    @ApolloJsonValue("${gzh.reply.video.refresh.job.filter.wxIds:[]}")
    private List<String> filterWxIds;
    @Value("${gzh.reply.video.refresh.job.topNum:2}")
    private Integer topNum;

    private final static ExecutorService pool = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(1000),
            new ThreadFactoryBuilder().setNameFormat("GzhReplyVideoRefreshJob-%d").build(),
            new ThreadPoolExecutor.AbortPolicy());

    @XxlJob("gzhReplyVideoRefreshJob")
    public ReturnT<String> gzhReplyVideoRefreshJob(String param) {
        String dt =DateUtil.getBeforeDayDateString("yyyy-MM-dd");
        if (StringUtils.isNotEmpty(param)) {
            dt = param;
        }
        List<AdPutCreativeComponentCostData> list = adApiService.getCreativeComponentsCost(dt);
        if (CollectionUtils.isEmpty(list)) {
            return ReturnT.SUCCESS;
        }
        // 按公众号分组
        Map<String, List<AdPutCreativeComponentCostData>> costDataMap = list.stream()
                .filter(o ->CollectionUtils.isNotEmpty(o.getComponentIds()))
                .collect(Collectors.groupingBy(AdPutCreativeComponentCostData::getWxId));
        CountDownLatch cdl = new CountDownLatch(costDataMap.size());
        // 获取所有投流账号信息
        String accountMapSql = "SELECT account_id, account_name from loghubods.feishu_wechat_mp_account_base where account_status = '开';";
        List<Record> accountList = OdpsUtil.getOdpsData(accountMapSql);
        Map<String, String> accountMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(accountList)) {
            for (Record record : accountList) {
                String accountId = record.getString(0);
                String accountName = record.getString(1);
                accountMap.put(accountId, accountName);
            }
        }
        // 服务号投流账号
        String fwhAccountMapSql = "SELECT account_id, account_name from loghubods.feishu_wechat_fwh_account_base where account_status = '开';";
        List<Record> fwhAccountList = OdpsUtil.getOdpsData(fwhAccountMapSql);
        if (CollectionUtils.isNotEmpty(fwhAccountList)) {
            for (Record record : fwhAccountList) {
                String accountId = record.getString(0);
                String accountName = record.getString(1);
                accountMap.put(accountId, accountName);
            }
        }

        // 获取公众号信息
        List<String> nameList = new ArrayList<>(accountMap.values());
        List<GhDetail> ghDetailList = ghDetailService.getGhdetailByNames(nameList);
        Map<String, GhDetail> ghDetailMap = ghDetailList.stream().collect(Collectors.toMap(GhDetail::getGhName, ghDetail -> ghDetail));
        for (Map.Entry<String, List<AdPutCreativeComponentCostData>> entry : costDataMap.entrySet()) {
            pool.submit(() -> {
                try {
                    replaceGZHReplyVideo(entry.getKey(), entry.getValue(), ghDetailMap, accountMap);
                } finally {
                    cdl.countDown();
                }
            });
        }
        try {
            cdl.await();
        } catch (InterruptedException e) {
            log.error("GzhReplyVideoRefreshJob error", e);
        }
        return ReturnT.SUCCESS;
    }

    private void replaceGZHReplyVideo(String wxId, List<AdPutCreativeComponentCostData> costDataList,
                                      Map<String, GhDetail> ghDetailMap,
                                      Map<String, String> accountMap) {
        if (filterWxIds.contains(wxId)) {
            return;
        }
        String accountName = accountMap.get(wxId);
        if (StringUtils.isEmpty(accountName)) {
            return;
        }
        GhDetail ghDetail = ghDetailMap.get(accountName);
        if (ghDetail == null) {
            return;
        }
        Map<String, JSONObject> creativeIdTextMap = analysisImageText(costDataList);
        log.info("GzhReplyVideoRefreshJob accountName:{} creativeIdTextMap:{}", accountName, JSONObject.toJSONString(creativeIdTextMap));
        // 按cost排序 获取top2内容
        List<JSONObject> sortedList = creativeIdTextMap.entrySet().stream()
                .sorted((o1, o2) -> o2.getValue().getLong("cost").compareTo(o1.getValue().getLong("cost")))
                .limit(topNum)
                .map(Map.Entry::getValue)
                .collect(Collectors.toList());
        List<VideoDetail> searchVideos = new ArrayList<>();
        List<String> existTitles = new ArrayList<>();
        for (JSONObject obj : sortedList) {
            String text = obj.getString("title");
            String keywordPrompt = getKeyWordPrompt(text);
            AIResult aiResult = deepSeekApiService.request(keywordPrompt, null, null, false);
            if (aiResult.isSuccess()) {
                List<String> keywords = JSONObject.parseArray(aiResult.getResponse().getChoices().get(0).getMessage().getContent(), String.class);
                log.info("GzhReplyVideoRefreshJob accountName:{} text:{} keywords:{}", accountName, text, keywords);
                VideoDetail videoDetail = getVideoDetail(keywords, searchVideos, existTitles);
                if (videoDetail != null) {
                    existTitles.add(videoDetail.getTitle());
                    existTitles.add(text);
                    videoDetail.setTitle(text);
                    videoDetail.setCover(obj.getString("coverImgUrl"));
                    searchVideos.add(videoDetail);
                }
            }
        }
        if (searchVideos.size() == topNum) {
            // 更新视频
            updateVideoReply(ghDetail, searchVideos);
        }
    }

    private String getKeyWordPrompt(String text) {
        // 提取关键词
        String keywordPrompt =
                "# Role\n" +
                        "你是一位世界顶级的短视频SEO专家。你擅长剥离标题中的修饰语和状态词，精准捕捉用户真正想搜索的“核心实体”或“核心话题”。\n" +
                        "\n" +
                        "# Task\n" +
                        "分析给定的视频标题，提取 **1个 或 2个** 最具搜索价值的关键词。\n" +
                        "\n" +
                        "# Constraints (必须严格执行)\n" +
                        "1. **字数限制**：每个关键词必须 **≤ 3个汉字**。\n" +
                        "2. **数量限制**：输出 1 到 2 个关键词。如果只有一个核心词，不要强行凑数，只输出一个。\n" +
                        "3. **选词优先级 (核心逻辑)**：\n" +
                        "   - **最高优先级**：核心名词、实体（如：燕子、粮食、早餐）。\n" +
                        "   - **次优先级**：具有明确分类属性的动词（如：剪辑、做菜）。\n" +
                        "4. **负面清单 (严禁提取)**：\n" +
                        "   - **剔除状态词/结果词**：如“过期”、“消失”、“变质”、“最好”、“几点”等描述物体状态或程度的词。\n" +
                        "   - **剔除虚词**：如“的”、“了”、“吗”。\n" +
                        "   - **剔除泛词**：如“今天”、“才知道”、“告诉”。\n" +
                        "5. **输出格式**：仅输出JSON数组，无其他字符。\n" +
                        "\n" +
                        "# Few-Shot Examples (学习选词逻辑)\n" +
                        "Input: 今天才知道5种粮食不怕过期！放越久越好！\n" +
                        "Output: [\"粮食\"]\n" +
                        "(解释：剔除“过期”，因为它只是粮食的一个状态，用户搜的是粮食)\n" +
                        "\n" +
                        "Input: 今年燕子消失了 你知道怎么回事吗？\n" +
                        "Output: [\"燕子\"]\n" +
                        "(解释：剔除“消失”，保留核心生物实体)\n" +
                        "\n" +
                        "Input: 新手如何快速学会剪映剪辑\n" +
                        "Output: [\"剪映\",\"剪辑\"]\n" +
                        "(解释：两个词都是核心技能点，且都在3字内)\n" +
                        "\n" +
                        "Input: 冰箱总是结冰怎么办\n" +
                        "Output: [\"冰箱\",\"结冰\"]\n" +
                        "(解释：“结冰”虽是状态，但“冰箱结冰”是常见故障搜索词，故保留；若无法判断，优先保实体)\n" +
                        "\n" +
                        "# Input\n" +
                        "内容是： {{text}} \n" +
                        "\n" +
                        "# Output\n" +
                        "请基于上述规则，输出最终的JSON：";
        keywordPrompt = keywordPrompt.replace("text", text);
        return keywordPrompt;
    }

    private Map<String, JSONObject> analysisImageText(List<AdPutCreativeComponentCostData> costDataList) {
        Map<String, JSONObject> creativeIdTextMap = new HashMap<>();
        for (AdPutCreativeComponentCostData costData : costDataList) {
            for (AdPutCreativeComponentCostData.AdPutTencentComponent component : costData.getComponentList()) {
                String imageUrl = component.getImageUrl();
                try {
                    // download & upload to oss
                    String fileName = String.format("growth/image/%s_%d.jpg", costData.getCreativeId(), System.currentTimeMillis());
                    String ossImageUrl = AliOssFileTool.downloadAndSaveInOSS(fileName, imageUrl, "image/jpeg");
                    // 调用gemini-3-pro模型提取图片中的文字
                    String prompt = "识别图片里的文字，直接输出图片里的文字标题，但是不要输出图片里右下角的字，比如“点开看看”“看这里”等，仅输出标题，不要有多余的文字输出";
                    GoogleLLMResult result = aigcApiService.gemini("gemini-2.0-flash", prompt, Arrays.asList(ossImageUrl));
                    String text = result.getResult();
                    text = text.replaceAll("\\n", "");
                    for (String existText : creativeIdTextMap.keySet()) {
                        if (TitleSimilarCheckUtil.isSimilar(text, existText, TitleSimilarCheckUtil.SIMILARITY_THRESHOLD)) {
                            text = existText;
                            break;
                        }
                    }
                    JSONObject obj = creativeIdTextMap.getOrDefault(text, new JSONObject());
                    Long cost = obj.getLong("cost");
                    if (Objects.isNull(cost)) {
                        cost = costData.getCost();
                        obj.put("cost", cost);
                        obj.put("title", text);
                        obj.put("coverImgUrl", ossImageUrl);
                    } else {
                        cost += costData.getCost();
                        obj.put("cost", cost);
                    }
                    creativeIdTextMap.put(text, obj);
                    break;
                } catch (Exception e) {
                    log.error("GzhReplyVideoRefreshJob analysisImageText error, imageUrl:{}", imageUrl, e);
                }
            }
        }
        return creativeIdTextMap;
    }

    private VideoDetail getVideoDetail(List<String> keywords, List<VideoDetail> searchVideos, List<String> existTitles) {
        VideoDetail videoDetail = null;
        int maxRetries = 3;
        int retryCount = 0;
        while (retryCount < maxRetries) {
            try {
                videoDetail = searchVideoByKeyword(keywords, searchVideos, existTitles);
                break;
            } catch (Exception e) {
                retryCount++;
                log.error("GzhReplyVideoRefreshJob searchVideoByKeyword error, retry count: {}/{}", retryCount, maxRetries, e);
                if (retryCount >= maxRetries) {
                    break;
                }
            }
        }
        return videoDetail;
    }

    private VideoDetail searchVideoByKeyword(List<String> keywords, List<VideoDetail> searchVideos, List<String> existTitles) {
        if (CollectionUtils.isNotEmpty(keywords)) {
            String searchVideoSql = "SELECT v.id, v.title, v.cover_img_path\n" +
                    "FROM videoods.wx_video v\n" +
                    "join videoods.wx_video_status vs on v.id = vs.video_id\n" +
                    "where (v.title like '%" + String.join("%' or v.title like '%", keywords) + "%') and v.status = 1 and vs.audit_status = 5\n" +
                    "order by v.play_count_total desc limit 10;";
            List<Record> videoList = OdpsUtil.getOdpsData(searchVideoSql);
            if (CollectionUtils.isNotEmpty(videoList)) {
                for (Record record : videoList) {
                    Long videoId = Long.parseLong(record.getString(0));
                    String title = record.getString(1);
                    // 过滤重复视频
                    boolean filter = false;
                    for (VideoDetail searchVideo : searchVideos) {
                        if (searchVideo.getId().equals(videoId)) {
                            filter = true;
                            break;
                        }
                    }
                    // 过滤重复标题
                    if (!filter && CollectionUtils.isNotEmpty(existTitles)) {
                        for (String existTitle : existTitles) {
                            if (TitleSimilarCheckUtil.isSimilar(title, existTitle, TitleSimilarCheckUtil.SIMILARITY_THRESHOLD)) {
                                filter = true;
                                break;
                            }
                        }
                    }
                    if (filter) {
                        continue;
                    }
                    String cover = record.getString(2);
                    VideoDetail videoDetail = new VideoDetail();
                    videoDetail.setId(videoId);
                    videoDetail.setCover(CdnUtil.getOssHttpUrl(cover));
                    videoDetail.setTitle(title);
                    return videoDetail;
                }
            }
        }
        return null;
    }

    private void updateVideoReply(GhDetail ghDetail, List<VideoDetail> searchVideos) {
        log.info("GzhReplyVideoRefreshJob accountName:{} updateVideoReply, oldVideoIds: {}, replaceVideos: {}",
                ghDetail.getGhName(), ghDetail.getVideoIds(), JSONObject.toJSONString(searchVideos));
        GhDetailVo ghDetailVo = new GhDetailVo();
        ghDetailVo.setId(ghDetail.getId());
        ghDetailVo.setAccountId(ghDetail.getGhId());
        ghDetailVo.setAccountName(ghDetail.getGhName());
        ghDetailVo.setCategory1(ghDetail.getCategory1());
        ghDetailVo.setStrategyStatus(ghDetail.getStrategyStatus());
        ghDetailVo.setType(ghDetail.getType());
        ghDetailVo.setAutoreplySendMinigramNum(topNum);
        ghDetailVo.setVideoIds(searchVideos.stream().map(VideoDetail::getId).collect(Collectors.toList()));
        List<GhDetailVo.VideoDetail> videoDetailList = new ArrayList<>();
        for (int i = 0; i < searchVideos.size(); i++) {
            VideoDetail videoDetail = searchVideos.get(i);
            GhDetailVo.VideoDetail videoDetailVo = new GhDetailVo.VideoDetail();
            videoDetailVo.setVideoId(videoDetail.getId());
            videoDetailVo.setSort(i + 1);
            videoDetailVo.setTitle(dealTitleLength(videoDetail.getTitle()));
            videoDetailVo.setCover(videoDetail.getCover());
            videoDetailList.add(videoDetailVo);
        }
        ghDetailVo.setVideoList(videoDetailList);
        ghDetailService.updateDetail(ghDetailVo, new HashMap<>());
    }

    private String dealTitleLength(String title) {
        if (StringUtils.isBlank(title)) {
            return title;
        }
        if (title.length() > 20) {
            title = title.substring(0, 19) + "…";
        }
        return title;
    }

    @XxlJob("syncGzhAutoreplyBehaviorUvTotalJob")
    public ReturnT<String> syncGzhAutoreplyBehaviorUvTotalJob(String param) {
        String dt = DateUtil.getBeforeDayDateString("yyyyMMdd");
        if (StringUtils.isNotEmpty(param)) {
            dt = param;
        }
        Long now = System.currentTimeMillis();
        GzhAutoreplyBehaviorUvTotalExample example = new GzhAutoreplyBehaviorUvTotalExample();
        example.createCriteria().andDtEqualTo(dt);
        List<GzhAutoreplyBehaviorUvTotal> list = gzhAutoreplyBehaviorUvTotalMapper.selectByExample(example);
        if (CollectionUtils.isNotEmpty(list)) {
            return ReturnT.SUCCESS;
        }
        // 公众号自动回复数据统计
        String sql = String.format(
                "SELECT 合作方\n" +
                        ",公众号id\n" +
                        ",访问人数\n" +
                        ",首层访问人数\n" +
                        ",dt\n" +
                        "FROM loghubods.gzh_autoreply_behavior_uv_total\n" +
                        "WHERE dt = %s ;", dt);
        List<Record> dataList = OdpsUtil.getOdpsData(sql);
        if (CollectionUtils.isNotEmpty(dataList)) {
            List<GzhAutoreplyBehaviorUvTotal> saveList = new ArrayList<>();
            for (Record record : dataList) {
                String channel = (String) record.get(0);
                String ghId = (String) record.get(1);
                Integer uv = parseInteger(record.get(2));
                Integer firstLevel = parseInteger(record.get(3));
                GzhAutoreplyBehaviorUvTotal item = new GzhAutoreplyBehaviorUvTotal();
                item.setDt(dt);
                item.setChannel(channel);
                item.setUv(uv);
                item.setFirstLevel(firstLevel);
                item.setGhId(ghId);
                item.setCreateTimestamp(now);
                saveList.add(item);
            }
            if (CollectionUtils.isNotEmpty(saveList)) {
                ghDetailMapperExt.deleteGzhAutoreplyBehaviorUvTotal(dt);
                ghDetailMapperExt.batchInsertGzhAutoreplyBehaviorUvTotal(saveList);
            }
        }
        return ReturnT.SUCCESS;
    }

    private Integer parseInteger(Object value) {
        try {
            return Integer.parseInt((String) value);
        } catch (NumberFormatException e) {
            return 0;
        }
    }
}
