package com.taais.biz.controller;


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.mybatisflex.core.query.QueryWrapper;
import com.taais.biz.domain.DataAugmentation;
import com.taais.biz.domain.bo.DataAugmentationBo;
import com.taais.biz.domain.bo.DataAugmentationResultBo;
import com.taais.biz.domain.bo.VideoStableStartResultBo;
import com.taais.biz.domain.vo.DataAugmentationVo;
import com.taais.biz.domain.vo.TaskDictDataVo;
import com.taais.biz.service.IVideoStableService;
import com.taais.common.core.service.OssService;
import com.taais.system.domain.SysDictData;
import com.taais.system.domain.SysOss;
import com.taais.system.service.ISysDictDataService;
import com.taais.system.service.ISysOssService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.apache.commons.compress.archivers.ar.ArArchiveEntry;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.taais.common.core.core.domain.CommonResult;
import com.taais.common.excel.utils.ExcelUtil;
import com.taais.common.log.annotation.Log;
import com.taais.common.log.enums.BusinessType;
import com.taais.common.web.annotation.RepeatSubmit;
import com.taais.common.web.core.BaseController;
import jakarta.annotation.Resource;
import com.taais.biz.service.IDataAugmentationService;

import com.taais.common.core.core.page.PageResult;

/**
 * 数据增强Controller
 *
 * @author 0
 * 2024-08-30
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/dataAugmentation")
public class DataAugmentationController extends BaseController {
    @Resource
    private IDataAugmentationService dataAugmentationService;
    @Autowired
    private ISysOssService ossService;
    @Autowired
    private ISysDictDataService sysDictDataService;
    @Autowired
    private IVideoStableService videoStableService;
    @GetMapping("/compare/num/{task_id}")

    public CommonResult getCompareNum(@PathVariable("task_id") Long taskId) {
        return CommonResult.success(dataAugmentationService.getCompareNum(taskId));
    }


    private static Path getImageAtPathIdx(Path inputPath, int idx) throws IOException {
        try (Stream<Path> paths = Files.list(inputPath)) {
            return paths.sorted()
                .skip(idx)
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("Index " + idx + " is out of bounds for the list of files in " + inputPath));
        }
    }
    //提取文件名称中数字进行排序
    private static int extractNumber(String fileName) {
        Pattern pattern = Pattern.compile("^\\d+");
        Matcher matcher = pattern.matcher(fileName);
        if (matcher.find()) {
            return Integer.parseInt(matcher.group());
        }
        // 如果文件名不是以数字开头，则返回一个很大的数，使其排在最后
        return -1;
    }
    @GetMapping("/compare/{task_id}/{idx}")
    public ResponseEntity<Map<String,List<String>>> getCompareImages(@PathVariable("task_id") Long taskId, @PathVariable("idx") int idx) {
        try {
            Map<String, List<String>> images = new HashMap<>();
            ArrayList<String> stable = new ArrayList<>();
            ArrayList<String> origin = new ArrayList<>();
            DataAugmentation dataAugmentation = dataAugmentationService.getById(taskId);
            Path inputPath = Paths.get(dataAugmentation.getInputPath());
            Path outputPath = Paths.get(dataAugmentation.getOutputPath());
//            System.out.println("inputPath: " + inputPath.toString());
//            System.out.println("outputPath: " + outputPath.toString());
            if (!Files.exists(inputPath) || !Files.isDirectory(inputPath)) {
                System.out.println("输入路径不存在或不是目录:" + inputPath.toString());
                origin.add("输入路径不存在或不是目录:" + inputPath.toString());
                images.put("error", origin);
                return ResponseEntity.status(500).body(images);
            }
            if (!Files.exists(outputPath) || !Files.isDirectory(outputPath)) {
                System.out.println("输出路径不存在或不是目录:" + outputPath.toString());
                origin.add("输出路径不存在或不是目录:" + outputPath.toString());
                images.put("error", origin);
                return ResponseEntity.status(500).body(images);
            }
            Path imagePath = getImageAtPathIdx(inputPath, idx);  //按照自然排序获取索引为idx的imagePath
            List<String> outputFileList = new ArrayList<>(); //初始化结果文件list
            List<String> inputFileList = new ArrayList<>(); //初始化输入文件list

            String taskType = dataAugmentation.getTaskType();
            //图像拼接算法、目标毁伤评估有多张输入图片，则imagePath是个目录
            if ("侦察图像拼接算法_sift".equals(taskType) || "侦察图像拼接算法_coordinate".equals(taskType) || "目标毁伤评估".equals(taskType)) {
                String lastDirectoryName = imagePath.getFileName().toString();
                inputPath = imagePath;
                outputPath = outputPath.resolve(lastDirectoryName);  //得到算法输出的结果目录

                if (Files.exists(outputPath) && Files.isDirectory(outputPath)) {
                    Stream<Path> outFilePathStream = Files.list(outputPath);
                    // 检查流中是否有下一个元素
                    outputFileList = outFilePathStream
                        .filter(Files::isRegularFile)  // 只选择常规文件（排除子目录、排除图像拼接算法_sift输入中的txt文件）
                        .filter(path -> !path.toString().toLowerCase().endsWith(".txt")).map(path -> {
                            return path.getFileName().toString();
                        }).collect(Collectors.toList());
                    if ("目标毁伤评估".equals(taskType)) {
                        QueryWrapper queryWrapper = new QueryWrapper();
                        queryWrapper.eq("dict_type", "biz_data_augmentation");
                        queryWrapper.eq("dict_label", "目标毁伤评估必须输出文件名称");
                        List<SysDictData> list = sysDictDataService.list(queryWrapper);
                        if (list.isEmpty()) {
                            origin.add("未在数据字典中定义目标毁伤评估必须输出文件名称");
                            images.put("error", origin);
                            return ResponseEntity.status(500).body(images);
                        } else {
                            String[] split = list.get(0).getDictValue().split(",");
                            for (String fileName: split) {
                                if (!outputFileList.contains(fileName)) {
                                    origin.add("输出目录不存在结果文件：" + fileName);
                                    images.put("error", origin);
                                    return ResponseEntity.status(500).body(images);
                                }
                            }
                        }
                        outputFileList.sort(Comparator.comparingInt(DataAugmentationController::extractNumber));
                    }
                } else {
                    System.out.println("图像拼接算法任务：" + dataAugmentation.getId() + "未创建结果目录！");
                    origin.add("图像拼接算法任务：" + dataAugmentation.getId() + "未创建结果目录！");
                    images.put("error", origin);
                    return ResponseEntity.status(500).body(images);
                }
                Stream<Path> inputFilePathStream = Files.list(imagePath);
                inputFileList = inputFilePathStream
                    .filter(Files::isRegularFile)  // 只选择常规文件（排除子目录、排除图像拼接算法_sift输入中的txt文件）
                    .filter(path -> !path.toString().toLowerCase().endsWith(".txt")).map(path -> {
                            return path.getFileName().toString();
                    }).collect(Collectors.toList());
            } else {
                //算法输入是一对一时，输出文件名称和输入文件名称相同
                String inputFileName = imagePath.getFileName().toString();
                inputFileList.add(inputFileName);
                outputFileList.add(inputFileName);
            }

            if (inputFileList.isEmpty()) {
                System.out.println(inputPath.toString() + "：输入文件为空" );
                origin.add(inputPath.toString() + "：输入文件为空");
                images.put("error", origin);
                return ResponseEntity.status(500).body(images);
            }
            if (outputFileList.isEmpty()) {
                System.out.println(outputFileList.toString() + "：输出文件为空" );
                origin.add(outputFileList.toString() + "：输入文件为空");
                images.put("error", origin);
                return ResponseEntity.status(500).body(images);
            }
            for (String inputFileName: inputFileList) {
                Path inputFilePath = inputPath.resolve(inputFileName);
                origin.add(Base64.getEncoder().encodeToString(Files.readAllBytes(inputFilePath)));
            }
            for (String outputFileName: outputFileList) {
                Path outputFilePath = outputPath.resolve(outputFileName);
//                if (!Files.exists(outputFilePath)) {
//                    System.out.println("结果文件不存在:" + outputFilePath.toString());
//                    return ResponseEntity.status(500).build();
//                }
                stable.add(Base64.getEncoder().encodeToString(Files.readAllBytes(outputFilePath)));
            }
            images.put("origin", origin);
            images.put("stable", stable);

            // 返回Map
            return ResponseEntity.ok(images);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.status(500).build();
        }
    }

    @PostMapping("/get_result")
    public CommonResult getResult(@Valid @RequestBody DataAugmentationResultBo dataAugmentationResultBo) {
        return dataAugmentationService.getResult(dataAugmentationResultBo);
    }

    @GetMapping("/start/{id}")
    public CommonResult start(@PathVariable("id") Long id) {
        return dataAugmentationService.start(id);
    }

    @GetMapping("/stop/{id}")
    public CommonResult stop(@PathVariable("id") Long id) {
        return dataAugmentationService.stop(id);
    }

    /**
     * 查询数据增强列表
     */
    @SaCheckPermission("demo:dataAugmentation:list")
    @GetMapping("/list")
    public CommonResult<PageResult<DataAugmentationVo>> list(DataAugmentationBo dataAugmentationBo) {
        return CommonResult.success(dataAugmentationService.selectPage(dataAugmentationBo));
    }

    /**
     * 导出数据增强列表
     */
    @SaCheckPermission("demo:dataAugmentation:export")
    @Log(title = "数据增强", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, @RequestBody String zipDirPath) {

        try {
            // 假设你已经知道ZIP文件的路径
//            String zipFilePath = dataAugmentationVo.getOutputPath() + ".zip";
//            System.out.println(dataAugmentationVo.toString());

            String zipFilePath = zipDirPath.substring(1, zipDirPath.length() - 1) + ".zip";
            System.out.println( zipFilePath);
            File zipFile = new File(zipFilePath);
            String fileName = zipFile.getName();
            // 设置响应头
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);
            // 读取ZIP文件并写入响应流
            try (FileInputStream fis = new FileInputStream(zipFilePath)) {
                IOUtils.copy(fis, response.getOutputStream());
            }
            // 刷新输出流
            response.flushBuffer();
        } catch (IOException e) {
            e.printStackTrace();
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 获取数据增强详细信息
     */
    @SaCheckPermission("demo:dataAugmentation:query")
    @GetMapping(value = "/{id}")
    public CommonResult<DataAugmentationVo> getInfo(@PathVariable Long id) {
        return CommonResult.success(dataAugmentationService.selectById(id));
    }

    /**
     * 新增数据增强
     */
    @SaCheckPermission("demo:dataAugmentation:add")
    @Log(title = "数据增强", businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping
    public CommonResult<Void> add(@Validated @RequestBody DataAugmentationBo dataAugmentationBo) {
//        QueryWrapper queryWrapper = new QueryWrapper();
//        queryWrapper.eq("file_name", dataAugmentationBo.getUploadPath());
//        List<SysOss> list = ossService.list(queryWrapper);
//        SysOss oneByEntityId = list.get(0);
//        dataAugmentationBo.setInputOssId(oneByEntityId.getOssId());
        boolean inserted = dataAugmentationService.insert(dataAugmentationBo);
        if (!inserted) {
            return CommonResult.fail("新增数据增强记录失败！");
        }
        return CommonResult.success();
    }

    /**
     * 修改数据增强
     */
    @SaCheckPermission("demo:dataAugmentation:edit")
    @Log(title = "数据增强", businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PutMapping
    public CommonResult<Void> edit(@Validated @RequestBody DataAugmentationBo dataAugmentationBo) {
        Boolean updated = dataAugmentationService.update(dataAugmentationBo);
        if (!updated) {
            return CommonResult.fail("修改数据增强记录失败!");
        }
        return CommonResult.success();
    }

    /**
     * 删除数据增强
     */
    @SaCheckPermission("demo:dataAugmentation:remove")
    @Log(title = "数据增强", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public CommonResult<Void> remove(@PathVariable Long[] ids) {
        boolean deleted = dataAugmentationService.deleteByIds(ids);
        if (!deleted) {
            return CommonResult.fail("删除数据增强记录失败!");
        }
        return CommonResult.success();
    }

    /**
     * 获取日志字符串
     */
    @SaCheckPermission("demo:dataAugmentation:query")
    @GetMapping(value = "/log/{id}")
    public CommonResult<String> getLog(@PathVariable Long id) {
        DataAugmentation byId = dataAugmentationService.getById(id);
        String filePath = byId.getAlgorithmPath();
        try{
            Path path = Paths.get(filePath);
            if (!Files.exists(path)) {
                return CommonResult.fail( "日志文件" + filePath + "不存在！");
            }
            // 读取文件内容
            return CommonResult.success(new String(Files.readAllBytes(path)), "获取日志成功");
        } catch (Exception e) {
            return CommonResult.fail("日志文件" + filePath + "读取失败！");
        }
    }

    @SaCheckPermission("demo:dataAugmentation:query")
    @GetMapping(value = "/getTaskDictData")
    public CommonResult<List<TaskDictDataVo>> getTaskDictData() {
        ArrayList<TaskDictDataVo> taskDictDataVos = new ArrayList<>();
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("dict_type", "biz_data_augmentation");
        queryWrapper.eq("dict_label", "任务类型");
        List<SysDictData> taskTypeList = sysDictDataService.list(queryWrapper);
        for (SysDictData sysDictData: taskTypeList) {
            String dictValue = sysDictData.getDictValue();
            queryWrapper.clear();
            queryWrapper.eq("dict_type", "biz_data_augmentation");
            queryWrapper.eq("dict_label", dictValue + "超参配置");
            List<SysDictData> hyparamList = sysDictDataService.list(queryWrapper);
            if (hyparamList.isEmpty()) {
                return CommonResult.fail("未在type为biz_data_augmentation的字典数据中设置" + dictValue + "的超参配置");
            }
            TaskDictDataVo taskDictDataVo = new TaskDictDataVo();
            taskDictDataVo.setTaskType(dictValue);
            taskDictDataVo.setHyperparameterConfiguration(hyparamList.get(0).getDictValue());
            taskDictDataVos.add(taskDictDataVo);
        }
        return CommonResult.success(taskDictDataVos);
    }
}
