package com.taais.biz.controller;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.taais.biz.constant.BizConstant;
import com.taais.biz.domain.Data;
import com.taais.biz.domain.ObjectMatch;
import com.taais.biz.domain.bo.ObjectMatchBo;
import com.taais.biz.domain.vo.ObjectMatchVo;
import com.taais.biz.service.service.IObjectMatchService;
import com.taais.biz.service.service.impl.ObjectMatchServiceImpl;
import com.taais.common.core.config.TaaisConfig;
import com.taais.common.core.utils.StringUtils;
import com.taais.common.core.utils.file.FileUploadUtils;
import com.taais.common.core.utils.file.UnPackedUtil;
import com.taais.common.core.utils.uuid.UUID;
import com.taais.system.domain.vo.SysOssVo;
import com.taais.system.service.ISysOssService;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import cn.dev33.satoken.annotation.SaCheckPermission;
import lombok.extern.slf4j.Slf4j;
import net.lingala.zip4j.model.FileHeader;
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.common.core.core.page.PageResult;
import org.springframework.web.multipart.MultipartFile;

import static com.taais.biz.constant.BizConstant.*;

/**
 * 异源图像匹配Controller
 *
 * @author km
 * 2024-10-28
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/match")
@Slf4j
public class ObjectMatchController extends BaseController {
    @Resource
    private ObjectMatchServiceImpl objectMatchService;

    @Resource
    private ISysOssService sysOssService;

    /**
     * 查询异源图像匹配列表
     */
    @SaCheckPermission("demo:match:list")
    @GetMapping("/list")
    public CommonResult<PageResult<ObjectMatchVo>> list(ObjectMatchBo objectMatchBo) {
        return CommonResult.success(objectMatchService.selectPage(objectMatchBo));
    }

    /**
     * 导出异源图像匹配列表
     */
    @SaCheckPermission("demo:match:export")
    @Log(title = "异源图像匹配", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, ObjectMatchBo objectMatchBo) {
        List<ObjectMatchVo> list = objectMatchService.selectList(objectMatchBo);
        ExcelUtil.exportExcel(list, "异源图像匹配", ObjectMatchVo.class, response);
    }

    /**
     * 获取异源图像匹配详细信息
     */
    @SaCheckPermission("demo:match:query")
    @GetMapping(value = "/{id}")
    public CommonResult<ObjectMatchVo> getInfo(@PathVariable Long id) {
        return CommonResult.success(objectMatchService.selectById(id));
    }

    /**
     * 新增异源图像匹配
     */
    @SaCheckPermission("demo:match:add")
    @Log(title = "异源图像匹配", businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping
    public CommonResult<Void> add(@Validated @RequestBody ObjectMatchBo objectMatchBo) {
        boolean inserted = objectMatchService.insert(objectMatchBo);
        if (!inserted) {
            return CommonResult.fail("新增异源图像匹配记录失败！");
        }
        return CommonResult.success();
    }

    /**
     * 修改异源图像匹配
     */
    @SaCheckPermission("demo:match:edit")
    @Log(title = "异源图像匹配", businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PutMapping
    public CommonResult<Void> edit(@Validated @RequestBody ObjectMatchBo objectMatchBo) {
        Boolean updated = objectMatchService.update(objectMatchBo);
        if (!updated) {
            return CommonResult.fail("修改异源图像匹配记录失败!");
        }
        return CommonResult.success();
    }

    /**
     * 删除异源图像匹配
     */
    @SaCheckPermission("demo:match:remove")
    @Log(title = "异源图像匹配", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public CommonResult<Void> remove(@PathVariable Long[] ids) {
        boolean deleted = objectMatchService.deleteByIds(ids);
        if (!deleted) {
            return CommonResult.fail("删除异源图像匹配记录失败!");
        }
        return CommonResult.success();
    }

    @GetMapping("/execute")
    public CommonResult<Void> execute(String taskId) {
        ObjectMatchBo bo = objectMatchService.getById(Long.parseLong(taskId));
        bo.setStartTime(new Date());
        Map<String, String> params = new HashMap<>();

        params.put("bizId", String.valueOf(bo.getId()));
        params.put("bizType", TYPE_OBJ_MATCH);
        params.put("logPath", DOCKER_BASE_PATH + bo.getResultPath() + "/log.log");
        params.put("sourcePath", DOCKER_BASE_PATH +  bo.getPreprocessPath());
        params.put("resultPath", DOCKER_BASE_PATH + bo.getResultPath());
        params.put("otherParams", new JSONObject().toString());

        log.info("obj_match params: {}", params);

        try {
            String res = HttpUtil.post(MULTI_OBJ_MATCH_URL, JSONUtil.toJsonStr(params));
            bo.setStatus(TASK_STATUS_PROCESSING);
        } catch (Exception e) {
            log.error("HTTP请求失败",e);
            bo.setStatus(TASK_STATUS_FAILED);
            bo.setEndTime(new Date());
            bo.setCostSecond((bo.getEndTime().getTime() - bo.getStartTime().getTime()) / 1000);
            return CommonResult.fail("HTTP请求失败" + e.getMessage());
        } finally {
            objectMatchService.update(bo);
        }
        return CommonResult.success();
    }

    @GetMapping("/result")
    public CommonResult<List<String>> getResult(String taskId) {
        ObjectMatchBo bo = objectMatchService.getById(Long.parseLong(taskId));
        if (bo == null) {
            return CommonResult.fail("未找到任务", null);
        }
        String path = bo.getResultPath();
        File dir = new File(BizConstant.DOCKER_BASE_PATH + path + "/IR_VIS_obj_in_IR");
        List<String> res = new ArrayList<>();
        if (dir.exists()) {
            for (File file : dir.listFiles()) {
                res.add(file.getName());
            }
        }
        return CommonResult.success(res);
    }

    @PostMapping("/createTask")
    public CommonResult<Void> createTask(@RequestBody Map<String, String> params) throws IOException {
        String file = params.get("file");
        if (file == null) {
            return CommonResult.fail("请上传.zip压缩文件。");
        }
        ObjectMatchBo match = new ObjectMatchBo();
        match.setName(params.get("name"));
        match.setParameters(params.get("parameters"));
        match.setStatus(BizConstant.TASK_STATUS_PENDING);

        String path = BizConstant.DOCKER_OBJ_MATCH_PATH + "/" + UUID.randomUUID().toString();
        match.setPreprocessPath(path);

        SysOssVo _file = sysOssService.getById(Long.parseLong(file));
        String filePath = TaaisConfig.getProfile() + _file.getUrl().split("/profile")[1];
        ZipFileExtractor.extractZipFile(filePath, DOCKER_BASE_PATH + path);

        match.setResultPath(path + "/result");
        File dir = new File(DOCKER_BASE_PATH + match.getResultPath());
        if (!dir.exists()) {
            dir.mkdirs();
        }

        boolean res = objectMatchService.insert(match);
        return res ? CommonResult.success() : CommonResult.fail();
    }

    public static class ZipFileExtractor {

        public static void extractZipFile(String zipFilePath, String destDir) throws IOException {
            Path zipPath = Paths.get(zipFilePath);
            Path destDirPath = Paths.get(destDir);

            if (Files.notExists(destDirPath)) {
                Files.createDirectories(destDirPath);
            }

            try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(zipPath))) {
                ZipEntry entry = zis.getNextEntry();
                while (entry != null) {
                    Path extractedPath = destDirPath.resolve(entry.getName());

                    if (entry.isDirectory()) {
                        Files.createDirectories(extractedPath);
                    } else {
// Ensure parent directories exist
                        if (extractedPath.getParent() != null && Files.notExists(extractedPath.getParent())) {
                            Files.createDirectories(extractedPath.getParent());
                        }

// Write file content
                        try (BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(extractedPath))) {
                            byte[] buffer = new byte[1024];
                            int len;
                            while ((len = zis.read(buffer)) != -1) {
                                bos.write(buffer, 0, len);
                            }
                        }
                    }
                    zis.closeEntry();
                    entry = zis.getNextEntry();
                }
            }
        }

        public static void main(String[] args) {
            try {
                String zipFilePath = "path/to/your/zipfile.zip";
                String destDir = "path/to/your/destDir";
                extractZipFile(zipFilePath, destDir);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
