package com.lion.lionwebsite.Service;

import com.lion.lionwebsite.Dao.cache.ImageCacheMapper;
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.im4java.core.ConvertCmd;
import org.im4java.core.IM4JavaException;
import org.im4java.core.IMOperation;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.URI;
import java.util.*;

import static com.lion.lionwebsite.Util.CustomUtil.objectMapper;
import static com.lion.lionwebsite.Util.GalleryUtil.*;

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

    GalleryMapper galleryMapper;

    CollectMapper collectMapper;

    CustomConfigurationMapper configurationMapper;

    UserMapper userMapper;

    ShareFileMapper shareFileMapper;

    ImageCacheMapper imageCacheMapper;

    RemoteService remoteService;

    PushService pushService;

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

    /**
     * 创建任务
     * @param link             任务链接
     * @param targetResolution 目标分辨率
     * @param AuthCode         授权码（用于记录是谁下载的）
     * @return 提交结果
     */
    public String createTask(String link, String targetResolution, String AuthCode) {
        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) != 0) {
                    log.error("传送任务{}失败, 未知原因", gallery.getName());
                    response.failure("任务传送失败，未知原因");
                    pushService.taskCreateReport(user.getUsername(), link, response);
                    return response.toJSONString();
                }
            }
        } catch (ResolutionNotMatchException e) {
            response.failure("提交失败，分辨率不存在");
            pushService.taskCreateReport(user.getUsername(), link, response);
            return response.toJSONString();
        } catch (IOException e) {
            log.error(e.getMessage());
            response.failure("IO错误，可能是网络波动");
            pushService.taskCreateReport(user.getUsername(), link, response);
            return response.toJSONString();
        }

        //处理下载结果，将任务插入数据库并且更新每周用量
        if (gallery.getStatus().equals("已提交")) {
            response.success(gallery.toString());
            gallery.setDownloader(user.getId());
            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));
        } 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;
                    }
                }
            }

        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 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.getFirst().equals(user.getId())         //判断收藏
                && gallery.getDownloader() == user.getId()))                                                   //判断下载
            response.failure("删除失败，该本子已被别人收藏或你不是下载人");
        else {
            log.info("删除本子{}", gallery.getName());
            galleryMapper.deleteGalleryByGid(gallery.getGid());                                 //删除本子记录
        }
        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();
    }

    public String cacheImagesKey(String url) {
        Response response = Response.generateResponse();
        String gid = String.valueOf(GalleryUtil.parseGid(url));
        GidToKey gidToKey = imageCacheMapper.selectKeyByGid(gid);
        //已缓存过，直接返回
        if(gidToKey != null) {
            return response.success(objectMapper.valueToTree(gidToKey)).toJSONString();
        }

        try {
            gidToKey = new GidToKey();
            gidToKey.setGid(gid);
            gidToKey.setKey(url.split("/")[5].strip());
            ArrayList<ImageKeyCache> imageKeyCaches = GalleryUtil.parseImageKeys(url);
            gidToKey.setPages(imageKeyCaches.size());
            imageCacheMapper.insertGidToKey(gidToKey);
            for (ImageKeyCache imageKeyCache : imageKeyCaches)
                imageCacheMapper.insertImageKeyCache(imageKeyCache);
            response.success(objectMapper.valueToTree(gidToKey));
        }catch (IOException e){
            log.error(e.getMessage());
            response.failure("网络波动或其他异常");
        }
        return  response.toJSONString();
    }

    String[] suffixes = {".webp", ".gif"};
    public void getCachedImage(String gid, Integer page, HttpServletRequest request, HttpServletResponse response) {
        //检查文件夹是否存在
        File folder = new File(cachePath + gid);
        if(!folder.isDirectory())
            folder.mkdirs();

        //检查对应图片是否存在，存在则直接返回
        for (String suffix : suffixes) {
            if(new File(cachePath + gid + "/" + page + suffix).exists()){
                FileDownload.export(request, response, cachePath + gid + "/" + page + suffix);
                return;
            }
        }

        //检查该本子缓存是否存在
        GidToKey gidToKey = imageCacheMapper.selectKeyByGid(gid);
        if(gidToKey == null)
            try {
                log.error("未缓存gid:" + gid);
                response.sendError(404);
                return;
            }catch (IOException ignored){
                return;
            }

        synchronized (this){
                if(response.isCommitted()) {
                    log.info("连接已关闭: gid=" + gid + " page=" + page);
                    return;
                }

                String imageUrl = null;
                //获取该图片key
                ImageKeyCache imageKeyCache = imageCacheMapper.selectImageKeyCacheByGidAndPage(gid, page);
                if (imageKeyCache == null) {
                    CustomUtil.fourZeroFour(response);
                    return;
                }

                //获取图片地址
                for (int i = 0; i < 2; i++) {
                    imageUrl = GalleryUtil.getImageUrl(getMpvKey(gidToKey.toUrl()), imageKeyCache);
                    if (imageUrl != null)
                        break;
                    GalleryUtil.refreshMpvKey(gidToKey.toUrl());
                }

                if (imageUrl == null) {
                    CustomUtil.fourZeroFour(response);
                    log.error("获取图片url失败:gid=" + gid + " page=" + page + " imageKey=" + imageKeyCache.getImgkey());
                    return;
                }

                //下载图片，转格式并返回
                String suffix = imageUrl.substring(imageUrl.lastIndexOf("."));
                String imagePath = cachePath + gid + "/" + page + suffix;
                try {
                    new URI(imageUrl).toURL().openConnection().getInputStream().transferTo(new FileOutputStream(imagePath));
                }catch (Exception e){
                    log.error("下载图片失败:url" + imageUrl);
                    e.printStackTrace();
                    CustomUtil.fourZeroFour(response);
                    return;
                }
                if (!suffix.equals(".gif")) {
                    ConvertCmd convertCmd = new ConvertCmd(true);
                    IMOperation operation = new IMOperation();
                    operation.addImage(imagePath);
                    operation.format("webp");
                    operation.addImage(imagePath.replace(suffix, ".webp"));
                    try {
                        convertCmd.run(operation);
                        new File(imagePath).delete();
                        imagePath = imagePath.replace(suffix, ".webp");
                    } catch (IOException | IM4JavaException | InterruptedException e) {
                        log.error("文件" + imagePath + "转换失败");
                    }
                }
                FileDownload.export(request, response, imagePath);
        }
    }

    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);
            response.success(String.format("发送未下载完成本子至节点,%s本", galleries.length));
        }else{
            response.failure("当前没有未下载完成的本子");
        }

        return response.toJSONString();
    }
}
