package com.lion.lionwebsite.Service;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import com.lion.lionwebsite.Dao.cache.PageNameCacheMapper;
import com.lion.lionwebsite.Dao.normal.*;
import com.lion.lionwebsite.Domain.*;
import com.lion.lionwebsite.Exception.ResolutionNotMatchException;
import com.lion.lionwebsite.Error.ErrorCode;
import com.lion.lionwebsite.Util.CustomUtil;
import com.lion.lionwebsite.Util.FileDownload;
import com.lion.lionwebsite.Util.GalleryUtil;
import com.lion.lionwebsite.Util.Response;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.*;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

import static com.lion.lionwebsite.Util.CustomUtil.dateTimeFormatter;
import static com.lion.lionwebsite.Util.CustomUtil.fourZeroFour;

@Service
@Data
@Slf4j
public class GalleryManageService {
    String TargetPath = "/root/gallery/";

    int cacheSize = 100;

    Map<Integer, String> gid2name_cache = new HashMap<>();

    Map<Integer, Integer> gid2page_cache = new HashMap<>();

    Map<String, String> page2pageNameCache = new HashMap<>();

    GalleryMapper galleryMapper;

    CollectMapper collectMapper;

    CustomConfigurationMapper configurationMapper;

    UserMapper userMapper;

    ShareFileMapper shareFileMapper;

    TagMapper tagMapper;

    PageNameCacheMapper pageNameCacheMapper;

    RemoteService remoteService;

    PushService pushService;

    public GalleryManageService(GalleryMapper galleryMapper, CollectMapper collectMapper, CustomConfigurationMapper configurationMapper, UserMapper userMapper, ShareFileMapper shareFileMapper,
                                TagMapper tagMapper, PageNameCacheMapper pageNameCacheMapper, RemoteService remoteService, PushService pushService) {
        this.galleryMapper = galleryMapper;
        this.collectMapper = collectMapper;
        this.configurationMapper = configurationMapper;
        this.userMapper = userMapper;
        this.shareFileMapper = shareFileMapper;
        this.tagMapper = tagMapper;
        this.pageNameCacheMapper = pageNameCacheMapper;
        this.remoteService = remoteService;
        this.pushService = pushService;
    }

    /**
     * 创建任务
     * @param link             任务链接
     * @param targetResolution 目标分辨率
     * @param AuthCode         授权码（用于记录是谁下载的）
     * @return 提交结果
     */
    public String createTask(String link, String targetResolution, String AuthCode, List<Integer> tidS, byte mode) {
        Response response = Response.generateResponse();
        User user = userMapper.selectUserByAuthCode(AuthCode);
//        return Response._failure("调试中，请勿提交任务");

        if (remoteService.isDead()) {
            response.failure("节点挂了，找狮子处理");
            pushService.taskCreateReport(user.getUsername(), link, response);
            return response.toJSONString();
        }
        int gid;
        try {
            gid = Integer.parseInt(link.split("/")[4]);
        } catch (NumberFormatException e) {
            response.failure("链接错误");
            pushService.taskCreateReport(user.getUsername(), link, response);
            return response.toJSONString();
        }
        Gallery gallery;

        //判断数据库中是否有这个任务，有则返回状态
        if ((gallery = galleryMapper.selectGalleryByGid(gid)) != null) {
            response.failure("任务队列已有此任务，任务状态： " + gallery.getStatus() + " 请点击查找任务");
            pushService.taskCreateReport(user.getUsername(), link, response);
            return response.toJSONString();
        }

        //尝试下载本子，返回结果
        try {
            gallery = GalleryUtil.parse(link, true, targetResolution);
            if (gallery == null || !gallery.getStatus().equals("已提交")) {
                log.error("创建任务失败: {}，", link);
                response.failure("提交任务失败，未知原因，请检查链接是否正常");
                pushService.taskCreateReport(user.getUsername(), link, response);
                return response.toJSONString();
            } else {
                log.info("创建任务: {} 目标分辨率：{}", link, targetResolution);
                if (remoteService.addGalleryToQueue(gallery, mode) != 0) {
                    log.error("传送任务{}失败, 未知原因", gallery.getName());
                    response.failure("任务传送失败，未知原因");
                    pushService.taskCreateReport(user.getUsername(), link, response);
                    return response.toJSONString();
                }
            }
        } catch (ResolutionNotMatchException e) {
            e.printStackTrace();
            response.failure("提交失败，分辨率不存在");
            pushService.taskCreateReport(user.getUsername(), link, response);
            return response.toJSONString();
        } catch (IOException e) {
            e.printStackTrace();
            response.failure("IO错误，可能是网络波动");
            pushService.taskCreateReport(user.getUsername(), link, response);
            return response.toJSONString();
        }

        //处理下载结果，将任务插入数据库并且更新每周用量
        if (gallery.getStatus().equals("已提交")) {
            response.success(gallery.toString());
            gallery.setDownloader(user.getId());
            gallery.setMode(mode);
            galleryMapper.insertGallery(gallery);

            long usedAmount = Long.parseLong(configurationMapper.selectConfiguration(CustomConfiguration.WEEK_USED_AMOUNT).getValue());
            usedAmount += gallery.getFileSize();
            configurationMapper.updateConfiguration(CustomConfiguration.WEEK_USED_AMOUNT, String.valueOf(usedAmount));
            if (tidS != null)
                for (Integer tid : tidS)
                    if (tagMapper.selectTagExistById(tid) > 0)
                        tagMapper.markTag(gallery.getGid(), tid);
        } else {
            response.failure("提交失败，未知原因");
            galleryMapper.deleteGalleryByGid(gallery.getGid());
        }
        pushService.taskCreateReport(user.getUsername(), link, response);

        return response.toJSONString();
    }

    /**
     * 根据链接查询本子
     * @param link 链接
     * @return 查询结果
     */
    public String selectTaskByLink(String link) {
        Response response = Response.generateResponse();
        Integer gid = parseGid(link);
        Gallery gallery;
        if (gid != null)
            gallery = galleryMapper.selectGalleryByGid(gid);
        else {
            response.failure("链接错误");
            return response.toJSONString();
        }
        log.info("查询{}", link);

        //判断数据库中是否有这个任务，如果有则返回，如果没有则直接查询
        if (gallery == null)
            try {
                gallery = GalleryUtil.parse(link, false, null);
                if (gallery != null)
                    response.success(new ObjectMapper().valueToTree(gallery).toString());
                else
                    response.failure("查询失败");
            } catch (Exception e) {
                log.info(e.getMessage());
                response.failure("查询失败");
            }

        else
            response.success(new ObjectMapper().valueToTree(gallery).toString());

        return response.toJSONString();
    }

    /**
     * 通过gid查询本子
     *
     * @param gid gid
     * @return 查询结果
     */
    public String selectTaskByGid(int gid) {
        Response response = Response.generateResponse();
        Gallery gallery = galleryMapper.selectGalleryByGid(gid);

        if (gallery == null)
            response.failure("未找到该本子，请使用链接");

        else
            response.success(gallery.toString());

        return response.toJSONString();
    }

    /**
     * 查询所有本子
     *
     * @return 查询结果
     */
    public String selectAllGallery(int userId) {
        Response response = Response.generateResponse();
        Gallery[] galleries = galleryMapper.selectAllGallery();

        if (galleries == null) {
            response.failure("没有找到本子");
            return response.toJSONString();
        }

        ArrayList<Integer> galleryIds = collectMapper.selectGidByCollector(userId);
        Iterator<Integer> idIterator;

        if (!galleryIds.isEmpty())                              //如果该用户收藏了本子
            galleryLoop:for (Gallery gallery : galleries) {   //遍历本子
                idIterator = galleryIds.iterator();
                while (idIterator.hasNext()) {                  //遍历收藏的gid
                    Integer id = idIterator.next();
                    if (id.equals(gallery.getGid())) {           //如果找到对应的gid,修改对应本子的属性，删除当前gid，判断是否需要跳出或者结束循环
                        gallery.setCollect(true);
                        idIterator.remove();

                        if (galleryIds.isEmpty())
                            break galleryLoop;
                        else
                            continue galleryLoop;
                    }
                }
            }


        HashMap<Integer, ArrayList<Integer>> tagsMap = new HashMap<>();
        ArrayList<TagMark> tags = tagMapper.selectAllMark();

        for (TagMark tagMark : tags) {              //从数据库取出所有标记，然后筛选出 gid -> tids ，后面加个缓存
            tagsMap.computeIfAbsent(tagMark.getGid(), k -> new ArrayList<>());
            tagsMap.get(tagMark.getGid()).add(tagMark.getTid());
        }

        ArrayList<Integer> temp;
        for (Gallery gallery : galleries) {
            if ((temp = tagsMap.get(gallery.getGid())) != null) {
                gallery.setTags(new ArrayList<>());
                gallery.getTags().addAll(temp);
            }
        }

        response.success(new ObjectMapper().valueToTree(galleries).toString());
        return response.toJSONString();
    }

    /**
     * 查询未完成的本子
     *
     * @return 查询结果
     */
    public String selectUnDoneGallery() {
        Response response = Response.generateResponse();
        Gallery[] galleries = galleryMapper.selectUnDoneGalleries();

        if (galleries.length > 0)
            response.success(new ObjectMapper().valueToTree(galleries).toString());
        else
            response.failure();

        return response.toJSONString();
    }

    /**
     * 通过本子名查询本子
     *
     * @param name 名字
     * @return 查询结果
     */
    public String selectGalleryByName(String name) {
        Response response = Response.generateResponse();
        Gallery gallery = galleryMapper.selectGalleryByName("%" + name + "%");

        if (gallery != null)
            response.success(new ObjectMapper().valueToTree(gallery).toString());
        else
            response.failure("没有找到该名字的本子");

        return response.toJSONString();
    }

    /**
     * 查询用户下载的本子
     *
     * @param AuthCode 授权码（用于查询用户名）
     * @return 查询结果
     */
    public String selectGalleryByDownloader(String AuthCode) {
        Response response = Response.generateResponse();

        Gallery[] galleries = galleryMapper.selectGalleryByDownloader(userMapper.selectUserByAuthCode(AuthCode).getId());
        if (galleries.length > 0)
            response.success(new ObjectMapper().valueToTree(galleries).toString());
        else
            response.failure("您未下载本子");

        return response.toJSONString();
    }

//    /**
//     * 获取本子图片的名字
//     * @param gid gid
//     * @return    名字数组
//     */
//    public String selectOnlineFilename(Integer gid){
//        Response response = Response.generateResponse();
//        String path;
//
//        if((path = gid2name_cache.get(gid)) == null) {
//            Gallery gallery = galleryMapper.selectGalleryByGid(gid);
//
//            if (gallery == null) {
//                response.failure("本子不存在");
//                return response.toJSONString();
//            }
//
//            path = TargetPath + gallery.getName();
//            gid2name_cache.put(gid, path);
//            if(gid2name_cache.size() > cacheSize)
//                gid2name_cache.remove(gid2name_cache.keySet().iterator().next());
//        }
//
//        File file = new File(path);
//        if(!file.isDirectory()){
//            response.failure("本子文件已被删除");
//            return response.toJSONString();
//        }
//
//        File[] files = file.listFiles(pathname -> pathname.getName().endsWith(".webp") && !pathname.getName().startsWith("thumbnail"));
//        if(files == null || files.length == 0){
//            response.failure("本子文件丢失");
//            return response.toJSONString();
//        }
//
//        ArrayList<String> images = new ArrayList<>();
//        for(File image: files){
//            images.add(image.getName().replace(".webp", ""));
//        }
//        //字符串长度相等时比较字典顺序，不相等时比较长度
//        images.sort((s1, s2) ->
//             s1.length() == s2.length() ? s1.compareTo(s2): s1.length() - s2.length()
//        );
//
//        response.success(new ObjectMapper().valueToTree(images).toString());
//        return response.toJSONString();
//    }

    /**
     * 删除本子以及对应的文件（如果存在的话）
     *
     * @param gid gid
     * @return 删除结果
     */
    public String deleteGalleryByGid(Integer gid, String AuthCode) {
        Response response = Response.generateResponse();
        Gallery gallery = galleryMapper.selectGalleryByGid(gid);
        User user = userMapper.selectUserByAuthCode(AuthCode);
        if (gallery == null) {
            response.failure("删除失败，该本子不存在");
            return response.toJSONString();
        }

        ArrayList<Integer> collector = collectMapper.selectCollectorByGid(gallery.getGid());
        if (!(collector.isEmpty() || collector.size() == 1 && collector.get(0).equals(user.getId())         //判断收藏
                && gallery.getDownloader() == user.getId()))                                                   //判断下载
            response.failure("删除失败，该本子已被别人收藏或你不是下载人");
        else {
            log.info("删除本子{}", gallery.getName());
            galleryMapper.deleteGalleryByGid(gallery.getGid());                                 //删除本子记录
            ArrayList<Integer> tidS = tagMapper.selectTagByGid(gallery.getGid());
            for (Integer tid : tidS)
                tagMapper.decrTagUsage(tid);

            tagMapper.disMarkTagByGid(gallery.getGid());                                        //删除本子标记
            gid2name_cache.remove(gallery.getGid());                                            //删除本子缓存
            page2pageNameCache.remove(gallery.getName());                                       //移除页数缓存
            pageNameCacheMapper.deletePageNameByGid(gid);

            if (new File(TargetPath + "/" + gallery.getName()).isDirectory())           //删除本地缓存
                FileUtil.del(TargetPath + "/" + gallery.getName());
        }
        switch (remoteService.deleteGallery(gallery)) {
            case ErrorCode.IO_ERROR -> response.failure("本子:" + gallery.getName() + "删除失败，IO错误");
            case ErrorCode.FILE_NOT_FOUND -> response.failure("本子:" + gallery.getName() + "删除失败，文件不存在");
            case 0 -> response.success();
        }
        if (response.get("result").equals("failure"))
            log.info(response.getResult());
        return response.toJSONString();
    }

    /**
     * 获取每周额度以及上次重置时间
     * @return  查询结果
     */
    public String getWeekUsedAmount() {
        Response response = Response.generateResponse();
        CustomConfiguration weekUsedAmount = configurationMapper.selectConfiguration(CustomConfiguration.WEEK_USED_AMOUNT);
        CustomConfiguration lastResetAmountTime = configurationMapper.selectConfiguration(CustomConfiguration.LAST_RESET_AMOUNT_TIME);
        Map<String, String> data = new HashMap<>();

        data.put("weekUsedAmount", CustomUtil.fileSizeToString(Long.parseLong(weekUsedAmount.getValue())));
        data.put("lastResetAmountTime", lastResetAmountTime.getValue());

        response.success(new ObjectMapper().valueToTree(data).toString());
        return response.toJSONString();
    }

    /**
     * 获取在线图片
     * @param gid           gid
     * @param page      文件名
     * @param request       请求对象
     * @param response      响应对象
     */
    public void getOnlineImage(Integer gid, Short page, HttpServletRequest request, HttpServletResponse response){
        String name;

        //本子名缓存
        if((name = gid2name_cache.get(gid)) == null)                                //内存
            if((name = galleryMapper.selectGalleryNameByGid(gid)) == null) {          //数据库
                fourZeroFour(response);
                return;
            }
            else
                gid2name_cache.put(gid, name);

        //页数缓存
        Integer real_page;
        if((real_page = gid2page_cache.get(gid)) == null)
            real_page = galleryMapper.selectGalleryByGid(gid).getPages();

        //判断页数是否超出
        if(real_page < page || page < 0){
            fourZeroFour(response);
            return;
        }


        //页名缓存
        String pageName;
        if((pageName = page2pageNameCache.get(gid + String.valueOf(page))) == null)     //内存
            if((pageName = pageNameCacheMapper.selectPageName(gid, page)) == null)    //数据库
                if ((pageName = remoteService.queryPageName(name, page)) == null) {   //远程查询
                    fourZeroFour(response);
                    return;
                }
                 //插入数据库
                else
                    pageNameCacheMapper.insertPageNameCache(new PageNameCache(gid, page, pageName));
            //插入缓存
            else
                page2pageNameCache.put(gid + String.valueOf(page), pageName);


        //图片缓存
        File file = new File(TargetPath, name + "/" + pageName);
        if(!file.exists())                                          //硬盘
            if(remoteService.cachePreview(name, page, file) != 0) {  //远程
                fourZeroFour(response);
                return;
            }

        FileDownload.export(request, response, file.getAbsolutePath());
    }



    public String shareGallery(Integer gid, Integer expireHour){
        Response response = Response.generateResponse();
        Gallery gallery = galleryMapper.selectGalleryByGid(gid);
        Map<String, String> jsonObject = new HashMap<>();
        if(gallery == null){
            response.failure("本子不存在");
            return response.toJSONString();
        }

        File file = new File(TargetPath + gallery.getName() + ".zip");

        if(!file.isFile()){
            response.failure("本子文件不存在");
            return  response.toJSONString();
        }

        ShareFile shareFile = shareFileMapper.selectShareFileByFilePath(file.getAbsolutePath());
        if(shareFile != null){
            jsonObject.put("shareCode", shareFile.getShareCode());
            jsonObject.put("expireTime", dateTimeFormatter.format(LocalDateTime.ofInstant(shareFile.getExpireTime().toInstant(), ZoneId.systemDefault())));
            response.success(new ObjectMapper().valueToTree(jsonObject).toString());
            return response.toJSONString();
        }

        String ShareCode = RandomUtil.randomString(8);
        Calendar expireTime = Calendar.getInstance();

        expireTime.add(Calendar.HOUR, expireHour);
        shareFileMapper.insertShareFile(ShareCode, file.getAbsolutePath(), expireTime.getTime());
        jsonObject.put("shareCode", ShareCode);
        jsonObject.put("expireTime", dateTimeFormatter.format(expireTime.getTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()));
        response.success(new ObjectMapper().valueToTree(jsonObject).toString());

        return response.toJSONString();
    }

    public String resetUndone(){
        Response response = Response.generateResponse();

        if (remoteService.isDead()){
            response.failure("节点不在线，无法重置");
            return response.toJSONString();
        }

        Gallery[] galleries = galleryMapper.selectUnDoneGalleries();
        if(galleries != null && galleries.length != 0) {
            log.info("发送未下载完成本子至节点,{}本", galleries.length);
            for (Gallery gallery : galleries)
                remoteService.addGalleryToQueue(gallery, gallery.getMode());
            response.success(String.format("发送未下载完成本子至节点,%s本", galleries.length));
        }else{
            response.failure("当前没有未下载完成的本子");
        }

        return response.toJSONString();
    }

    public static Integer parseGid(String link){
        try {
            return Integer.parseInt(link.split("/g/")[1].split("/")[0]);
        }catch (IndexOutOfBoundsException e){
            return null;
        }
    }
}
