package com.fs.course.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.fs.common.core.domain.R;
import com.fs.common.utils.DateUtils;
import com.fs.common.utils.StringUtils;
import com.fs.company.domain.CompanyUser;
import com.fs.company.mapper.CompanyUserMapper;
import com.fs.course.config.CourseConfig;
import com.fs.course.domain.FsCourseDomainName;
import com.fs.course.domain.FsCourseLink;
import com.fs.course.domain.FsCourseRealLink;
import com.fs.course.domain.FsUserCourseVideo;
import com.fs.course.mapper.FsCourseDomainNameMapper;
import com.fs.course.mapper.FsCourseLinkMapper;
import com.fs.course.mapper.FsUserCourseVideoMapper;
import com.fs.course.param.FsCourseLinkCreateParam;
import com.fs.course.service.IFsCourseDomainNameService;
import com.fs.course.service.IFsCourseLinkService;
import com.fs.qw.domain.QwUser;
import com.fs.qw.mapper.QwUserMapper;
import com.fs.system.service.ISysConfigService;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

import static com.fs.course.utils.LinkUtil.generateRandomStringWithLock;

/**
 * 短链Service业务层处理
 *
 * @author fs
 * @date 2024-09-11
 */
@Service
@Slf4j
public class FsCourseLinkServiceImpl implements IFsCourseLinkService
{
    @Autowired
    private FsCourseLinkMapper fsCourseLinkMapper;
    @Autowired
    private ISysConfigService configService;

    @Autowired
    private FsCourseDomainNameMapper fsCourseDomainNameMapper;
    @Autowired
    private QwUserMapper qwUserMapper;
    @Autowired
    private FsUserCourseVideoMapper courseVideoMapper;
    @Autowired
    private CompanyUserMapper companyUserMapper;


    /**
     * 查询短链
     *
     * @param linkId 短链主键
     * @return 短链
     */
    @Override
    public FsCourseLink selectFsCourseLinkByLinkId(Long linkId)
    {
        return fsCourseLinkMapper.selectFsCourseLinkByLinkId(linkId);
    }

    /**
     * 查询短链列表
     *
     * @param fsCourseLink 短链
     * @return 短链
     */
    @Override
    public List<FsCourseLink> selectFsCourseLinkList(FsCourseLink fsCourseLink)
    {
        return fsCourseLinkMapper.selectFsCourseLinkList(fsCourseLink);
    }

    /**
     * 新增短链
     *
     * @param fsCourseLink 短链
     * @return 结果
     */
    @Override
    public int insertFsCourseLink(FsCourseLink fsCourseLink)
    {
        fsCourseLink.setCreateTime(DateUtils.getNowDate());
        return fsCourseLinkMapper.insertFsCourseLink(fsCourseLink);
    }

    /**
     * 修改短链
     *
     * @param fsCourseLink 短链
     * @return 结果
     */
    @Override
    public int updateFsCourseLink(FsCourseLink fsCourseLink)
    {
        return fsCourseLinkMapper.updateFsCourseLink(fsCourseLink);
    }

    /**
     * 批量删除短链
     *
     * @param linkIds 需要删除的短链主键
     * @return 结果
     */
    @Override
    public int deleteFsCourseLinkByLinkIds(Long[] linkIds)
    {
        return fsCourseLinkMapper.deleteFsCourseLinkByLinkIds(linkIds);
    }

    /**
     * 删除短链信息
     *
     * @param linkId 短链主键
     * @return 结果
     */
    @Override
    public int deleteFsCourseLinkByLinkId(Long linkId)
    {
        return fsCourseLinkMapper.deleteFsCourseLinkByLinkId(linkId);
    }

    private static final String realLink = "/courseH5/pages/course/learning?course=";
    private static final String shortLink = "/courseH5/pages/course/learning?s=";
    private static final String miniappRealLink = "/pages_course/video?course=";


    /**
     *创建应急短链
     * @param param
     * @return
     */
    @Transactional
    @Synchronized
    @Override
    public R createLinkUrl(FsCourseLinkCreateParam param)  {
        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
        FsCourseLink link = new FsCourseLink();
        link.setCompanyId(param.getCompanyId());
        link.setCompanyUserId(param.getCompanyUserId());
        link.setVideoId(param.getVideoId());
        link.setCourseId(param.getCourseId());
        link.setLinkType(1);//创建应急短链
//        link.setLinkUuid(UUID.randomUUID().toString());


        String randomString = generateRandomString();
        link.setLink(randomString);
        link.setCreateTime(new Date());

        Integer expireDays = (param.getDays() == null || param.getDays() == 0)
                ? config.getVideoLinkExpireDate()
                : param.getDays();

        // 使用 Java 8 时间 API 计算过期时间
        LocalDateTime sendDateTime = new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        LocalDateTime expireDateTime = sendDateTime.plusDays(expireDays-1);
        expireDateTime = expireDateTime.toLocalDate().atTime(23, 59, 59);
        Date updateTime = Date.from(expireDateTime.atZone(ZoneId.systemDefault()).toInstant());
        link.setUpdateTime(updateTime);

        // 设置过期时间
        link.setUpdateTime(updateTime);

        if (fsCourseLinkMapper.insertFsCourseLink(link)>0){
            FsCourseRealLink courseMap = new FsCourseRealLink();
            BeanUtils.copyProperties(link,courseMap);
            // 将实体类对象转换为 JSON 字符串
            String course = JSON.toJSONString(courseMap);
            link.setRealLink(realLink+course);
            if (fsCourseLinkMapper.updateFsCourseLink(link)>0){
                String domainName = getDomainName(param.getCompanyUserId(), config);
                String sortLink = domainName + shortLink + link.getLink();
                return R.ok("短链生成").put("url",sortLink);
            }
        }
        return R.error("短链生成失败！");
    }

    @Override
    public R createRoomLinkUrl(FsCourseLinkCreateParam param) {
        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
        FsCourseLink link = new FsCourseLink();
        BeanUtils.copyProperties(param,link);
        link.setLinkType(0);
        link.setIsRoom(1);
        FsCourseRealLink courseMap = new FsCourseRealLink();
        BeanUtils.copyProperties(link,courseMap);
        // 将实体类对象转换为 JSON 字符串
        String course = JSON.toJSONString(courseMap);
        link.setRealLink(realLink+course);
        String randomString = generateRandomString();
        link.setLink(randomString);
        link.setCreateTime(new Date());
        Integer expireDays = 0;
        if (param.getDays() == null || param.getDays() == 0){
            expireDays = config.getVideoLinkExpireDate();
        }else {
            expireDays = param.getDays();
        }
        // 设置过期时间
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(link.getCreateTime());
        calendar.add(Calendar.DAY_OF_MONTH, expireDays);
        link.setUpdateTime(calendar.getTime());
        if (fsCourseLinkMapper.insertFsCourseLink(link)>0){
            String domainName = getDomainName(param.getCompanyUserId(), config);
            String sortLink = domainName + shortLink + link.getLink();
            return R.ok("短链生成").put("url",sortLink);
        }
        return R.error("短链生成失败！");
    }

    @Override
    public R createLinkUrlWc(FsCourseLinkCreateParam param) {

        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);

        FsCourseLink link = new FsCourseLink();
        link.setCompanyId(param.getCompanyId());
        link.setQwUserId(param.getQwUserId());
        link.setCompanyUserId(param.getCompanyUserId());
        link.setVideoId(param.getVideoId());
        link.setCorpId(param.getCorpId());
        link.setCourseId(param.getCourseId());
        link.setQwExternalId(param.getQwExternalId());
        link.setLinkType(0);
        FsCourseRealLink courseMap = new FsCourseRealLink();
        BeanUtils.copyProperties(link,courseMap);
        // 将实体类对象转换为 JSON 字符串
        String course = JSON.toJSONString(courseMap);
        link.setRealLink(realLink+course );
        String randomString = generateRandomString();
        link.setLink(randomString);
        link.setCreateTime(param.getSendTime());
        Integer expireDays = 0;
        if (param.getDays() == null || param.getDays() == 0){
            expireDays = config.getVideoLinkExpireDate();
        }else {
            expireDays = param.getDays();
        }
        // 设置过期时间
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(param.getSendTime());
        calendar.add(Calendar.DAY_OF_MONTH, expireDays);
        link.setUpdateTime(calendar.getTime());
        if (fsCourseLinkMapper.insertFsCourseLink(link)>0){
            String domainName = getDomainName(param.getCompanyUserId(), config);
            String sortLink = domainName + shortLink + link.getLink();
            return R.ok("短链生成").put("url",sortLink);
        }
        return R.error("短链生成失败！");
    }

    @Override
    public String createLinkUrlWcmini(FsCourseLinkCreateParam param) {
        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);


        FsCourseLink link = createFsCourseLink(param.getCorpId(), param.getSendTime(), param.getCourseId(), param.getVideoId(), param.getQwUserId(),
                param.getCompanyUserId(), param.getCompanyId(), param.getQwExternalId(),3);

        FsCourseRealLink courseMap = new FsCourseRealLink();
        BeanUtils.copyProperties(link,courseMap);

        String courseJson = JSON.toJSONString(courseMap);
        String realLinkFull = miniappRealLink + courseJson;
        link.setRealLink(realLinkFull);

        Date updateTime = createUpdateTime(param.getDays(), param.getSendTime(), config);

        link.setUpdateTime(updateTime);
        //存短链-
        fsCourseLinkMapper.insertFsCourseLink(link);

        return link.getRealLink();
    }


    public FsCourseLink createFsCourseLink(String corpId, Date sendTime,Long courseId,Long videoId, String qwUserId,
                                           Long companyUserId, Long companyId,Long externalId,Integer type){
        // 手动创建 FsCourseLink 对象，避免使用 BeanUtils.copyProperties
        FsCourseLink link = new FsCourseLink();
        link.setCompanyId(companyId);
        link.setQwUserId(qwUserId);
        link.setCompanyUserId(companyUserId);
        link.setVideoId(videoId);
        link.setCorpId(corpId);
        link.setCourseId(courseId);
        link.setQwExternalId(externalId);
        link.setLinkType(type); //小程序
        String randomString = generateRandomStringWithLock();
        link.setLink(randomString);
        link.setCreateTime(sendTime);

        return link;
    }

    private String getDomainName(Long companyUserId,CourseConfig config){
        String domainName = companyUserMapper.selectDomainByUserId(companyUserId);
        if (StringUtils.isEmpty(domainName)){
            domainName = config.getRealLinkDomainName();
        }
        return domainName;
    }

    private Date createUpdateTime(Integer expiresDays, Date sendTime, CourseConfig config){

        Integer expireDays = (expiresDays == null || expiresDays == 0)
                ? config.getVideoLinkExpireDate()
                : expiresDays;

//         使用 Java 8 时间 API 计算过期时间
        LocalDateTime sendDateTime = sendTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        LocalDateTime expireDateTime = sendDateTime.plusDays(expireDays-1);
        expireDateTime = expireDateTime.toLocalDate().atTime(23, 59, 59);
        Date updateTime = Date.from(expireDateTime.atZone(ZoneId.systemDefault()).toInstant());

        return updateTime;
    }

    // 生成随机的八位数字字母大小写的字符串（改为生成随机不重复的雪花id）
    public static String generateRandomString() {
        // 可以在这里添加允许的符号字符，比如 "!@#$%^&*"
        String symbols = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        SecureRandom random = new SecureRandom();
        StringBuilder sb = new StringBuilder(8);

        for (int i = 0; i < 8; i++) {
            int index = random.nextInt(symbols.length());
            sb.append(symbols.charAt(index));
        }
        return sb.toString();
//        return IdUtil.getSnowflake(0, 0).nextIdStr();
    }

    @Override
    public R getRealLink(String link) {
        try {
            // URL解码
            String sLink = URLDecoder.decode(link, "UTF-8");

            // 从数据库中查找短链对应的真实链接
            FsCourseLink courseLink = fsCourseLinkMapper.selectFsCourseLinkByLink(sLink);
            if (courseLink != null) {
                // 获取当前时间
                Date currentTime = new Date();
                // 获取链接的更新时间（假设这个字段代表过期时间）
                Date updateTime = courseLink.getUpdateTime();

                // 判断是否过期
                if (currentTime.after(updateTime)) {
                    // 链接已过期
                    log.info("链接已过期: {}", sLink);
                    return R.error("链接已过期").put("realLink", sLink);
                } else {
                    // 链接仍然有效，返回真实链接
                    if (courseLink.getRealLink() == null) {
                        log.error("真实链接不存在, link: {}", sLink);
                        return R.error("真实链接不存在").put("realLink", sLink);
                    }
                    log.info("链接仍然有效: {}", sLink);
                    String json = configService.selectConfigByKey("course.config");
                    CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
                    String domainName = companyUserMapper.selectDomainByUserId(courseLink.getCompanyUserId());
                    if (StringUtils.isEmpty(domainName)){
                        domainName = config.getRealLinkDomainName();
                    }
                    String realLink = domainName+courseLink.getRealLink();
                    String imgUrl = "https://jiuzhouzaixian.obs.cn-southwest-2.myhuaweicloud.com/fs/20250425/1745561154024.png";
                    return R.ok().put("realLink",realLink ).put("config",config).put("headerImg",imgUrl);
                }
            } else {
                // 链接不存在或解析失败
                log.warn("URL解析错误或链接不存在: {}", sLink);
                return R.error("URL 解析错误或链接不存在").put("realLink", sLink);
            }

        } catch (UnsupportedEncodingException e) {
            // URL解码异常
            log.error("URL 解码失败: {}", e.getMessage(), e);
            return R.error("URL 解码失败").put("realLink", link);
        } catch (Exception e) {
            // 捕获其他异常并记录
            log.error("发生未知错误: {}", e.getMessage(), e);
            return R.error("发生未知错误，请稍后再试").put("realLink", link);
        }
    }


    @Override
    public void delCourseExpireLink() {
        List<Long> linkIds  = fsCourseLinkMapper.selectExpireLink();
        processDelCourseLink(linkIds);
    }

    private void processDelCourseLink(List<Long> linkIds) {
        // 定义批量删除的大小
        int batchSize = 1000;

        // 循环处理外部用户 ID，每次处理批量大小的子集
        for (int i = 0; i < linkIds.size(); i += batchSize) {

            int endIndex = Math.min(i + batchSize, linkIds.size());
            List<Long> batchList = linkIds.subList(i, endIndex);  // 获取当前批次的子集
            Long[] batchArray = batchList.toArray(new Long[0]);

            // 直接使用批次数据进行批量更新，不需要额外的 List
            try {
                fsCourseLinkMapper.deleteFsCourseLinkByLinkIds(batchArray);
                log.info("正在删除短链条数：{}",batchSize);
            } catch (Exception e) {
                // 记录异常日志，方便后续排查问题
                log.error("批量删除数据时发生异常，处理的批次起始索引为: " + i, e);
            }
        }
    }

    @Override
    public void updateLinks() {
        List<FsCourseLink> links = fsCourseLinkMapper.selectFsCourseLinkListUpdate();
        for (FsCourseLink link : links){
            String newUrl = link.getRealLink().replace("https://h5.cdwjyyh.com","");
            link.setRealLink(newUrl);
            fsCourseLinkMapper.updateFsCourseLink(link);
        }
    }

    @Override
    public R createLinkByMiniApp(FsCourseLinkCreateParam param) {
        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);

        FsCourseLink link = new FsCourseLink();
        link.setCompanyId(param.getCompanyId());
        link.setQwUserId(param.getQwUserId());
        link.setCompanyUserId(param.getCompanyUserId());
        link.setVideoId(param.getVideoId());
        link.setCorpId(param.getCorpId());
        link.setCourseId(param.getCourseId());
        link.setQwExternalId(param.getQwExternalId());
        link.setLinkType(3);
        String randomString = generateRandomString();
        link.setLink(randomString);

        //组装参数json
        FsCourseRealLink courseMap = new FsCourseRealLink();
        BeanUtils.copyProperties(link,courseMap);
        // 将实体类对象转换为 JSON 字符串
        String course = JSON.toJSONString(courseMap);
        link.setRealLink(miniappRealLink+course );

        link.setCreateTime(param.getSendTime());
        Integer expireDays = 0;
        if (param.getDays() == null || param.getDays() == 0){
            expireDays = config.getVideoLinkExpireDate();
        }else {
            expireDays = param.getDays();
        }
        // 设置过期时间
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(param.getSendTime());
        calendar.add(Calendar.DAY_OF_MONTH, expireDays);
        link.setUpdateTime(calendar.getTime());
        if (fsCourseLinkMapper.insertFsCourseLink(link)>0){
            return R.ok("短链生成").put("url",link.getRealLink());
        }
        return R.error("短链生成失败！");
    }
}
