package com.example.demo.controller;

import org.springframework.core.io.Resource;
import org.springframework.core.io.FileSystemResource;
import com.example.demo.model.StrAndEmail;
import com.example.demo.model.TreeModifyRequest;
import com.example.demo.model.Svg2PdfRequest;
import com.example.demo.result.ResponseData;
import com.example.demo.result.ResponseUtil;
import com.example.demo.service.UseService;

import com.example.demo.utils.DoPerlUtil;
import com.example.demo.utils.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import java.io.IOException;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
import java.nio.file.attribute.BasicFileAttributes;

@Slf4j
@RestController
// 不打包删除：@RequestMapping("/api")
@RequestMapping("/api")
public class UseController {

   
    @Autowired
    UseService useService;


    @Autowired
    RedissonClient redissonClient;

    // 静态变量 全局使用
    // 文件全名
    private String fullName;
    // 文件去后缀名
    private String shortName;
    // puuid
    private String retrievePuuid;
    private String doUniprot;
    private String pgapSelopt;
    /**
     * 以字符串的形式提交序列号
     *
     * @param data1
     * @return
     */    
    @PostMapping("message/postStr")
    public ResponseData postStr(@RequestBody StrAndEmail data1) {

        if ((data1.getStr() == null || data1.getStr().isEmpty()) || (data1.getEmail() == null || data1.getEmail().isEmpty())) {
            ResponseData data = new ResponseData();
            data.setCode(10000);
            data.setMessage("请输入序列号和接收邮箱");
            data.setSuccess(false);
            return data;
        }

        //        把序列号放入一个文件中

        String orgFilePath = FileUtils.strToFile(data1.getStr());


//        StrAndEmail strAndEmail = new StrAndEmail();
//        strAndEmail.setStr(orgFilePath);
//        strAndEmail.setEmail(data1.getEmail());
        data1.setStr(orgFilePath);

        UUID uuid = UUID.randomUUID();

        log.info("str_parm_uuid :" + uuid.toString());
        String puuid = uuid + "parm_uuid";
        log.info("xiangyangadd-puuid :" + puuid);
//        把参数传递到前端，下一次再把参数传给后端
        RBucket<StrAndEmail> rBucket = redissonClient.getBucket(puuid);
        rBucket.set(data1);
        rBucket.expire(7, TimeUnit.DAYS);

//        发送邮件

        int countFiles = FileUtils.countFiles("/home/ubuntu/Bio-server/upload_dir/");
        String count = String.valueOf(countFiles - 1);

        int last = orgFilePath.lastIndexOf("/");
        String filename = orgFilePath.substring(last + 1);
        
        log.info("截取提交的文件名为: " + filename);
        int i = filename.indexOf(".");
        String fuuid = filename.substring(0, i);
        StringBuffer buffer = new StringBuffer();
        
//      生成下载链接/home/ubuntu/Bio-server/workplace_filename/out_result.zip, 对应UseServiceImpl.java
        buffer.append("https://mgs.microbialgenomic.cn:8101/downloadFile?fuuid=");
        buffer.append(fuuid);

//      获取结果下载地址xiangyang 20240428
        this.fullName = filename;
        this.shortName = fuuid;
        this.retrievePuuid = puuid;
        
        // DoPerlUtil.doPerlEmail(count, buffer.toString(), data1.getEmail());
        log.info("xiangyangadd-fullName shortname puuid :", this.fullName + this.shortName + this.retrievePuuid);

        return new ResponseUtil<>().setData(uuid.toString(),
                "Please be patient as there are " + count + " tasks currently being processed ahead of yours. If you provide an email address, you will receive a notification once the task submission is successful or the task analysis is completed. Please make sure to check your inbox!");

    }


    /**
     * 新开一个任务来执行perl脚本
     * 提交序列号和邮箱的专用接口方法，如果需要添加内容，
     * 在psotStr括号内添加对应提交数据的数据类型的名称
     * <p>
     * str 序列号
     *
     * @return
     */
    @GetMapping("message/postUUID/after")
    public ResponseData postStrAfter(String puuid) {


        log.info("puuid = :" + puuid);
        RBucket<StrAndEmail> rBucket = redissonClient.getBucket(puuid + "parm_uuid");

        StrAndEmail strAndEmail = rBucket.get();
        if (strAndEmail == null) {
            return new ResponseUtil<>().setData("非法调用，不允许执行");
        }


        if ((strAndEmail.getStr() == null || strAndEmail.getStr().equals("")) || (strAndEmail.getEmail() == null || strAndEmail.getEmail().equals(""))) {
            return new ResponseUtil<>().setData("非法调用，不允许执行");
        }


        useService.postTxt(strAndEmail);


        return new ResponseUtil<>().setData("脚本执行完毕");

    }


    /**
     * 以文件的形式上传序列号
     *
     * @param file
     * @param email
     * @param sqlNum
     * @param threadNum
     * @return
     */
    @RequestMapping("message/postTxt")
    public ResponseData postTxt(@RequestParam("file") MultipartFile file, String email, int sqlNum, int threadNum, String doUniprot, String pgapSelopt) {
        this.doUniprot = doUniprot;
        this.pgapSelopt = pgapSelopt;

//        把获取到的文件存储在本地，返回文件的存储位置

        String filePath = FileUtils.fileStoreLocal(file);

        log.info(filePath);

        UUID uuid = UUID.randomUUID();

        log.info("txt_parm_uuid: " + uuid.toString());
        String puuid = uuid + "parm_uuid";

//        把参数传递到前端，下一次再把参数传给后端
        StrAndEmail strAndEmail = new StrAndEmail();
        strAndEmail.setStr(filePath);
        strAndEmail.setEmail(email);
        strAndEmail.setSqlNum(sqlNum);
        strAndEmail.setThreadNum(threadNum);
        strAndEmail.setDoUniprot(doUniprot);
        strAndEmail.setPgapSelopt(pgapSelopt);
        RBucket<StrAndEmail> rBucket = redissonClient.getBucket(puuid);
        rBucket.set(strAndEmail);
        rBucket.expire(7, TimeUnit.DAYS);


//        发送邮件

        int countFiles = FileUtils.countFiles("/home/ubuntu/Bio-server/upload_dir/");
        String count = String.valueOf(countFiles - 1);
        int last = filePath.lastIndexOf("/");
        String filename = filePath.substring(last + 1);

        log.info("截取提交的文件名为: " + filename);
        int i = filename.indexOf(".");
        String fuuid = filename.substring(0, i);

        StringBuffer buffer = new StringBuffer();
//        124.223.154.39:8101
//      生成下载链接/home/ubuntu/Bio-server/workplace_filename/out_result.zip, 对应UseServiceImpl.java
        buffer.append("https://mgs.microbialgenomic.cn:8101/downloadFile?fuuid=");
        buffer.append(fuuid);

//      获取结果下载地址xiangyang 20240428
        this.fullName = filename;
        this.shortName = fuuid;
        this.retrievePuuid = puuid;
        
        // DoPerlUtil.doPerlEmail(count, buffer.toString(), email);
        log.info("xiangyangadd-fullName shortname puuid :", this.fullName + this.shortName + this.retrievePuuid);

        // 调用check_uploadfile_totalFileNum.pl来检测上传的序列压缩包文件中的总文件数量 
        String fileFormatNumber = DoPerlUtil.uploadFormatPlusFileNumPerl(filePath); 
        // 使用split方法以制表符为分隔符切割字符串
        // 假设我们有一个数组或列表来存储文件格式数量和文件格式
        String[] fileFormatNumberArray = fileFormatNumber.split("\t");
        int fileNumber = Integer.parseInt(fileFormatNumberArray[0]);
        int fileFormat = Integer.parseInt(fileFormatNumberArray[1]);
        if (fileFormat == 1) {
            return new ResponseUtil<>().setData(uuid.toString(),
                "1");
        } else {
            return new ResponseUtil<>().setData(uuid.toString(),
                "Your upload file contains " + fileNumber + " genomes, and has been successfully submitted. Please be patient as there are " + count + " tasks currently being processed ahead of yours. If you provide an email address, you will receive a notification once the task submission is successful or the task analysis is completed. Please make sure to check your inbox!");
        }

    }


    /**
     * 获取下载文件
     *
     * @param fuuid
     * @param response
     * @return
     */
    @GetMapping("/downloadFile")
    public String downloadFile(String fuuid, HttpServletResponse response) {
        RBucket<String> rBucket = null;
        String path = null;
        try {
            rBucket = redissonClient.getBucket("file_uuid" + fuuid);
            path = rBucket.get();
        } catch (Exception e) {
            log.info("获取rBucket对象异常");
            return "The download link has expired. Please resubmit the task to obtain a new download link.";
        }

        if (path == null) {
            return "Please wait, your submitted task is currently in the queue, awaiting analysis.";
        }


        File file = new File(path);
        if (!file.exists()) {
            log.info("结果文件还未生成");

            return "Please wait, the analysis has not been completed yet.";
        }
        String fileName = file.getName();
        response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);
        download(response, file);

        return "Task is finished, please download.";

    }

//  待定分析完成后，返回变量--文件全名|文件去后缀名|Puuid--值到前端
    @GetMapping("/getUrlParam")
    public String getUrlParam(@RequestParam String param) {
        String site = fullName + "|" + shortName + "|" + retrievePuuid;
        fullName = "";
        shortName = "";
        retrievePuuid = "";
        return site;
    }

//  获取排队需分析的任务数量，返回变量值count到前端jobNum
    @GetMapping("/getJobNum")
    public ResponseEntity<String> JobNum() {
        int countFiles = FileUtils.countFiles("/home/ubuntu/Bio-server/upload_dir/");
        String count = String.valueOf(countFiles - 1);
        // 记录日志  
        log.info("Job number: {}, {}, {}", count);
        return ResponseEntity.ok(count);
    }
    
//  将基因组数据库统计表（/home/ubuntu/Bio-server/db/sum.tab）形成链接，在Vue3前段展示
//  假设文件存储在一个安全且可配置的目录中
    @GetMapping("/getTab")
    public String getTab(HttpServletResponse response, @RequestParam(defaultValue = "sum.tab") String fileName) throws IOException {
         
        StringBuffer resultdirPath = new StringBuffer();
        // 结果文件夹地址/home/ubuntu/Bio-server/workplace_
        resultdirPath.append("/home/ubuntu/Bio-server/db/");
        resultdirPath.append(fileName);

        // 拼接后的地址就是文件夹的绝对路径
        File file = new File(String.valueOf(resultdirPath));

        if (!file.exists()) {
            return "The target file cannot be found.";
        }

        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
        
        download(response, file);
        
        return "文件已经返回，请点击下载：" +
                "https://mgs.microbialgenomic.cn:8101/getTab?fileName=" + fileName;
    }
    

//  通过页面输入rsubmitId（缺少后缀信息）来获取已经存在的分析结果，主要是通过匹配到结果文件全名matchedSubfolderName，返回变量--文件全名|文件去后缀名
    @GetMapping("/result")  
    public String getResult(@RequestParam String rsubmitId) {  
        // rsubmitId从前端Retrieve result表单处获取  
        // 指定文件夹路径  
        Path directory = Paths.get("/home/ubuntu/Bio-server/");
        String result = "Job ID does not exist"; // 初始化结果为默认消息
        // 提供的字符串变量，用于匹配子文件夹名
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory)) {
            for (Path subfolder : stream) {
                // 如果子项是一个文件夹并且名字包含提供的字符串
                if (Files.isDirectory(subfolder) && subfolder.getFileName().toString().contains(rsubmitId)) {
                    // 将匹配到的子文件夹名赋值给一个变量
                    String matchedSubfolderName = subfolder.getFileName().toString();
                    System.out.println("Matched subfolder: " + matchedSubfolderName);
                    int i = matchedSubfolderName.indexOf(".");
                    String matchedShortName = matchedSubfolderName.substring(0, i);
                    result = matchedSubfolderName + "|" + matchedShortName;
                    matchedShortName = "";
                    matchedSubfolderName = "";
                    break; // 找到后退出循环
                }
            }
        } catch (IOException | DirectoryIteratorException e) {
            e.printStackTrace();
        }
        return result;
    }


//  20240824添加，treeString、bootStrap从前端获取
//  通过前端传入treeString和boostrap两个参数，然后执行afterphylo.pl后获得最新的treeString，最后将treeString传递给前段
    @PostMapping("/treemodify")
    public ResponseEntity<String> postTreemodify(@RequestBody TreeModifyRequest request) {  
        // 从 request 对象中获取 treeString 和 bootstrapArgv  
        String treeString = request.getTreeString();  
        String bootStrap = request.getBootstrapArgv();  
        String annoTab = request.getAnnoTab();
        // 调用你的工具类或方法来处理数据  
        String newtreeString = DoPerlUtil.doPerltree(treeString, bootStrap, annoTab);  
        // 记录日志  
        log.info("bootStrap|newtreeString|annoTab: {}, {}, {}", bootStrap, newtreeString, annoTab);  
        // 返回响应  
        return ResponseEntity.ok(newtreeString);  
    }
//  20250112添加，pdfString从前端获取
//  通过前端传入pdfString参数，然后执行svg2figure.py后获得pdf文件，最后将pdf文件传递给前段
    @PostMapping("/svg2pdf")
    public ResponseEntity<Resource> postsvg2pdf(@RequestBody Svg2PdfRequest request) {
        try {
            // 从 request 对象中获取 pdfString
            String pdfString = request.getPdfString();
            // 调用你的工具类或方法来处理数据  
            File pdfFile = DoPerlUtil.doPythonSvgToPdf(pdfString);  
            // 记录日志  
            log.info("PDF file created successfully: {}", pdfFile.getName());  
        
            // 准备返回的文件资源
            Resource resource = new FileSystemResource(pdfFile);

            // 设置 HTTP 响应头
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + pdfFile.getName() + "\"");
            headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_PDF_VALUE);
            // 返回文件资源作为响应
            return ResponseEntity.ok()
                .headers(headers)
                .body(resource);
        } catch (IOException e) {
            // 处理异常，可以记录错误日志并返回适当的错误响应
            log.error("Error creating PDF file", e);
            return ResponseEntity.status(500).body(null);
        } 
    } 
    
//  将提交的序列或装配号文件（/home/ubuntu/Bio-server/temp/XXXX）形成链接，供DELL服务器下载获取
    @GetMapping("/getFile")
    public String getFile(HttpServletResponse response, String fileName) {

        StringBuffer buffer = new StringBuffer();

        // 临时文件夹地址/home/ubuntu/Bio-server/temp/
        buffer.append("/home/ubuntu/Bio-server/temp/");
        buffer.append(fileName);

        // 拼接后的地址就是文件夹的绝对路径
        File file = new File(String.valueOf(buffer));

        if (!file.exists()) {
            return "The target file cannot be found.";
        }

        download(response, file);
        
        return "文件已经返回，请点击下载：" +
                "https://mgs.microbialgenomic.cn:8101/getFile?fileName=" + fileName;

    }
    // 检查文件是否存在的API
    private static final String BASE_PATH = "/home/ubuntu/Bio-server/workplace_";
    @GetMapping("/checkFile")
    public ResponseEntity<String> checkFile(@RequestParam String fileName) {
        String fullPath = BASE_PATH + fileName + "/out_result/raxml_workplace/core_gene_alignment_SNP.phy.raxml.support";
        File file = new File(fullPath);
        System.out.println("检查发现进化树文件路径为: " + fullPath);
        if (file.exists() && file.isFile()) {
            // 文件存在，返回成功响应
            return ResponseEntity.ok("File exists with name: " + fileName);
        } else {
            // 文件不存在，返回404错误
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body("File not found with path: " + fullPath);
        }
    }
    /**
     * 生成链接/home/ubuntu/Bio-server/workplace_filename/out_result/raxml_workplace/core_gene_alignment_SNP.phy.raxml.support
     */
    @GetMapping("/outFile")
    public String outFile(HttpServletResponse response, String fileName) {

        // StringBuffer resultdirPath = new StringBuffer();
        // 结果文件夹地址/home/ubuntu/Bio-server/workplace_
        // resultdirPath.append("/home/ubuntu/Bio-server/workplace_");
        // resultdirPath.append(fileName);
        // resultdirPath.append("/out_result/raxml_workplace/core_gene_alignment_SNP.phy.raxml.support");
        String treeFilePath = "/home/ubuntu/Bio-server/workplace_" + fileName + "/out_result/raxml_workplace/core_gene_alignment_SNP.phy.raxml.support";
        String coreAlignmentAln = "/home/ubuntu/Bio-server/workplace_" + fileName + "/out_result/panGenome_core_gene_alignment.aln";

        // 拼接后的地址就是文件夹的绝对路径
        File file1 = new File(treeFilePath);
        File file2 = new File(coreAlignmentAln);
        
        if (file2.exists()) {
            long fileSize = file2.length();
            if (fileSize == 0) {
                return "Core gene number is 0.";
            } else {
                if (!file1.exists()) {
                    return "The target file cannot be found.";
                }
            }
        } else {
            if (!file1.exists()) {
                return "The target file cannot be found.";
            }
        }
        
        int i = fileName.indexOf(".");
        String sName = fileName.substring(0, i);
        response.setHeader("Content-Disposition", "attachment; filename=\"" + sName + "\"");
        
        download(response, file1);
        System.out.println("outFile: " + "fileName" + fileName + "shortName" + sName);
        return "文件已经返回，请点击下载：" +
                "https://mgs.microbialgenomic.cn:8101/outFile?fileName=" + sName;

    }
    
    
    /**
     * 为了不通过提交的方式获取out_result.zip，使用outResultZip生成链接 —xiangyang20250113
     */
    @GetMapping("/outResultZip")
    public String outResultZip(HttpServletResponse response, String subId) {
    
        Path work_directory = Paths.get("/home/ubuntu/Bio-server/");
        String outResultZipPath = null; // 初始化结果为默认消息
        // 提供的字符串变量，用于匹配子文件夹名
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(work_directory)) {
            for (Path subworkfolder : stream) {
                // 如果子项是一个文件夹并且名字包含提供的字符串
                if (Files.isDirectory(subworkfolder) && subworkfolder.getFileName().toString().contains(subId)) {
                    // 将匹配到的子文件夹名赋值给一个变量
                    String matchedSubWorkFolderName = subworkfolder.getFileName().toString();
                    System.out.println("Matched subworkfolder: " + matchedSubWorkFolderName);
                    outResultZipPath = "/home/ubuntu/Bio-server/" + matchedSubWorkFolderName + "/out_result.zip";
                    System.out.println("检查发现out_result.zip文件路径为: " + outResultZipPath);
                    break; // 找到后退出循环
                }
            }
        } catch (IOException | DirectoryIteratorException e) {
            e.printStackTrace();
            return null;
        }
        
        // 拼接后的地址就是文件夹的绝对路径
        File fileZip = new File(outResultZipPath);
        
        if (!fileZip.exists()) {
            return "out_result.zip cannot be found:" + outResultZipPath;
        }
        response.setHeader("Content-Disposition", "attachment; filename=\"" + "out_result_" + subId + ".zip" + "\"");
        download(response, fileZip);
        return "文件已经返回，请点击下载：" +
            "https://mgs.microbialgenomic.cn:8101/outResultZip?subId=" + subId;
    }
    
    
    /**
     * 对一个文件夹下的所有文件生成链接/home/ubuntu/Bio-server/workplace_filename/out_result, 对应UseServiceImpl.java
     */
    @GetMapping("/outbatchFile")
    public String outbatchFile(HttpServletResponse response, String fileName) {
        String baseDirPath = "/home/ubuntu/Bio-server/workplace_" + fileName;
        String baseUrl = "https://mgs.microbialgenomic.cn:8101/outbatchFile?fileName=" + fileName + "/";

        List<String> urls = new ArrayList<>();

        try {
            Path folderPath = Paths.get(baseDirPath);

            Files.walkFileTree(folderPath, new SimpleFileVisitor<Path>() {

                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                    String relativePath = folderPath.relativize(file).toString().replace(File.separator, "/");
                    String fileUrl = baseUrl + relativePath; // 注意：这里我们没有在baseUrl后加斜杠

                    urls.add(fileUrl); // 将生成的URL添加到列表中
                    System.out.println(fileUrl); // 打印URL以供调试
                    return FileVisitResult.CONTINUE;
                }

                // 可以选择性地覆盖其他方法，如visitFileFailed等
            });

        } catch (IOException e) {
            e.printStackTrace();
        }

        return ""; // 返回生成的URL列表
    }

    /**
     * 把目标文件以流的形式通过response返回给客户端
     *
     * @param response
     * @param file
     */
    private void download(HttpServletResponse response, File file) {
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        OutputStream os = null;

        try {
            os = response.getOutputStream();
            fis = new FileInputStream(file);
            bis = new BufferedInputStream(fis);
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = fis.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if (bis != null) {
                bis.close();
            }
            if (fis != null) {
                fis.close();
            }
            if (os != null) {
                os.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}



