package cd.casic.ci.process.process.service.testCase.impl;


import cd.casic.ci.process.dto.req.testCase.TestCaseManagerQueryReq;
import cd.casic.ci.process.dto.req.testCase.TestCaseManagerReq;
import cd.casic.ci.process.dto.resp.testCase.TestCaseInfoResp;
import cd.casic.ci.process.dto.resp.sftpFile.FileBase64DownloadResp;
import cd.casic.ci.process.dto.resp.testCase.TestCaseManagerResp;
import cd.casic.ci.process.process.converter.TestCaseManagerConverter;
import cd.casic.ci.process.process.dao.testCase.TestCaseInfoDao;
import cd.casic.ci.process.process.dao.testCase.TestCaseManagerDao;
import cd.casic.ci.process.process.dataObject.testCase.TestCaseInfo;
import cd.casic.ci.process.process.dataObject.testCase.TestCaseManager;
import cd.casic.ci.process.process.service.testCase.TestCaseInfoService;
import cd.casic.ci.process.process.service.testCase.TestCaseManagerService;
import cd.casic.ci.commons.properties.TargetFileUploadProperties;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.framework.security.dal.user.AdminUserDO;
import cd.casic.framework.tenant.core.service.AdminUserServiceImpl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jcraft.jsch.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author HopeLi
 * @version v1.0
 * @ClassName PipelineServiceImpl
 * @Date: 2025/5/13 10:31
 * @Description:
 */
@Service
@Slf4j
public class TestCaseManagerServiceImpl extends ServiceImpl<TestCaseManagerDao, TestCaseManager> implements TestCaseManagerService {

    @Resource
    private TestCaseManagerDao testCaseManagerDao;

    @Resource
    private TestCaseInfoDao testCaseInfoDao;

    @Resource
    private AdminUserServiceImpl adminUserService;

    @Resource
    private TargetFileUploadProperties fileUploadProperties;

    @Resource
    private TestCaseInfoService testCaseInfoService;
    @Resource
    private TargetFileUploadProperties properties;
    @Override
    public String create(TestCaseManagerReq req) {
        TestCaseManager testCaseManager = TestCaseManagerConverter.INSTANCE.toBean(req);
        testCaseManagerDao.insert(testCaseManager);
        return testCaseManager.getId();
    }

    @Override
    public void delete(String id){
        TestCaseManager testCaseManager = testCaseManagerDao.selectById(id);
        if (ObjectUtils.isEmpty(testCaseManager)){
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"数据错误请联系管理员");
        }
        testCaseManagerDao.deleteById(id);

        List<TestCaseInfo> testCaseInfos = testCaseInfoDao.selectList(new QueryWrapper<TestCaseInfo>().eq("test_case_manager_id", id));
        if (!ObjectUtils.isEmpty(testCaseInfos)){
            testCaseInfoDao.deleteByIds(testCaseInfos.stream().map(TestCaseInfo::getId).toList());
        }
    }



    @Override
    public void updateTestCaseManager(TestCaseManagerReq req) {
        TestCaseManager testCaseManager = testCaseManagerDao.selectById(req.getId());
        if (ObjectUtils.isEmpty(testCaseManager)){
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"数据错误请联系管理员");
        }
        TestCaseManagerConverter.INSTANCE.updateReqCopyToBean(req,testCaseManager);
        testCaseManagerDao.updateById(testCaseManager);
    }

    @Override
    public List<TestCaseManagerResp> findList(TestCaseManagerQueryReq query) {
        QueryWrapper<TestCaseManager> wrapper = new QueryWrapper<>();
        List<TestCaseManager> testCaseManagers = testCaseManagerDao.selectList(wrapper);

        if (ObjectUtils.isEmpty(testCaseManagers)){
            return new ArrayList<>();
        }
        List<TestCaseManagerResp> respList = TestCaseManagerConverter.INSTANCE.toRespList(testCaseManagers);
        respList.forEach(this::setUserName);
        return respList;
    }



    @Override
    public PageResult<TestCaseManagerResp> findPage(TestCaseManagerQueryReq query) {
        QueryWrapper<TestCaseManager> wrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(query.getName())){
            wrapper.like("name", query.getName());
        }
        if (!StringUtils.isEmpty(query.getType())){
            wrapper.eq("type", query.getType());
        }
        Page<TestCaseManager> testCaseManagerPage = testCaseManagerDao.selectPage(new Page<>(query.getPageNo(), query.getPageSize()), wrapper);
        if (ObjectUtils.isEmpty(testCaseManagerPage)){
            return new PageResult<>();
        }
        List<TestCaseManagerResp> respList = TestCaseManagerConverter.INSTANCE.toRespList(testCaseManagerPage.getRecords());
        respList.forEach(this::setUserName);
        List<String> list = respList.stream().map(TestCaseManagerResp::getId).toList();
        List<TestCaseInfoResp> testCaseInfos = testCaseInfoService.findByManagerIds(list);
        Map<String, List<TestCaseInfoResp>> collect = testCaseInfos.stream().collect(Collectors.groupingBy(TestCaseInfoResp::getTestCaseManagerId));
        fullManagerFileInfo(respList,collect);
        return new PageResult<>(respList,testCaseManagerPage.getTotal(),testCaseManagerPage.getCurrent(),testCaseManagerPage.getSize());
    }


    @Override
    public TestCaseManagerResp findById(String id) {
        TestCaseManager testCaseManager = testCaseManagerDao.selectById(id);
        if (ObjectUtils.isEmpty(testCaseManager)){
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"数据错误请联系管理员");
        }
        TestCaseManagerResp testCaseManagerResp = TestCaseManagerConverter.INSTANCE.toResp(testCaseManager);
        setUserName(testCaseManagerResp);
        return testCaseManagerResp;
    }

    @Override
    public FileBase64DownloadResp downLoadById(String id) {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(bos)){
            JSch jsch = new JSch();
            Session session = jsch.getSession(properties.getUsername(), properties.getRemoteHost(), properties.getRemotePort());
            session.setPassword(properties.getPassword());

            // 跳过 host key 检查
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);

            session.connect();
            ChannelSftp sftp = (ChannelSftp) session.openChannel("sftp");
            sftp.connect();
            List<TestCaseInfoResp> byManagerIds = testCaseInfoService.findByManagerIds(Collections.singletonList(id));

            for (TestCaseInfoResp byManagerId : byManagerIds) {
                InputStream inputStream = sftp.get(byManagerId.getTestFilePath());
                String fileName = byManagerId.getFileName();
                ZipEntry zipEntry = new ZipEntry(fileName);
                zipOutputStream.putNextEntry(zipEntry);
                IOUtils.copy(inputStream,zipOutputStream);
                zipOutputStream.closeEntry();
                inputStream.close();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        byte[] byteArray = bos.toByteArray();
        String file = Base64.getEncoder().encodeToString(byteArray);
        FileBase64DownloadResp testCaseManagerDownloadResp = new FileBase64DownloadResp();
        testCaseManagerDownloadResp.setFile(file);
        testCaseManagerDownloadResp.setFileName("SEED.zip");
        return testCaseManagerDownloadResp;
    }


    private void setUserName(TestCaseManagerResp testCaseManagerResp) {
        if (!StringUtils.isEmpty(testCaseManagerResp.getCreator())){
            AdminUserDO user = adminUserService.getUser(Long.valueOf(testCaseManagerResp.getCreator()));
            if (!ObjectUtils.isEmpty(user)){
                testCaseManagerResp.setCreatorName(user.getUsername());
            }
        }

        if (!StringUtils.isEmpty(testCaseManagerResp.getUpdater())){
            AdminUserDO user = adminUserService.getUser(Long.valueOf(testCaseManagerResp.getUpdater()));
            if (!ObjectUtils.isEmpty(user)){
                testCaseManagerResp.setUpdaterName(user.getUsername());
            }
        }
    }



    private void deleteRemoteFolder(String folderPath) throws JSchException, InterruptedException {
        JSch jsch = new JSch();
        Session session = null;
        ChannelExec channel = null;
        String username = fileUploadProperties.getUsername();
        String host = fileUploadProperties.getRemoteHost();
        Integer port = 22;
        String password = fileUploadProperties.getPassword();

        try {
            session = jsch.getSession(username, host, port);
            session.setPassword(password);

            // 设置首次登录不自动添加密钥
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();

            // 构建删除命令（递归删除）
            String command = String.format("rm -rf %s", folderPath);

            channel = (ChannelExec) session.openChannel("exec");
            channel.setCommand(command);
            channel.setErrStream(System.err);
            channel.connect();

            // 等待命令执行完成
            while (!channel.isClosed()) {
                Thread.sleep(100);
            }

        } finally {
            if (channel != null) {
                channel.disconnect();
            }
            if (session != null) {
                session.disconnect();
            }
        }
    }
    private void fullManagerFileInfo(List<TestCaseManagerResp> respList,Map<String,List<TestCaseInfoResp>> caseInfoMap){
        if (CollectionUtils.isEmpty(respList)||CollectionUtils.isEmpty(caseInfoMap)) {
            return;
        }
        for (TestCaseManagerResp managerInfo : respList) {
            List<TestCaseInfoResp> testCaseInfos = caseInfoMap.get(managerInfo.getId());
            if (CollectionUtils.isEmpty(testCaseInfos)) {
                continue;
            }
            Integer size = 0;
            Integer fileCount = testCaseInfos.size();
            for (TestCaseInfoResp testCaseInfo : testCaseInfos) {
                JSONArray array= JSONArray.parseArray(testCaseInfo.getTestFileList());
                if (!array.isEmpty()) {
                    for (int i = 0; i < array.size(); i++) {
                        JSONObject jsonObject = array.getJSONObject(i);
                        Integer fileSize = jsonObject.getInteger("size");
                        size+=fileSize;
                    }
                }
            }
            managerInfo.setFileCount(fileCount);
            managerInfo.setFileSize(getSizeStr(size*2));
        }
    }
    private String getSizeStr(Integer size){
        Integer devid=1;
        int level = 0; // 0 -byte 1-kb 2-mb 3-gb
        while (size/devid>=1024){
            devid*=1024;
        };
        return switch (level) {
            case 0 -> size / devid + "byte";
            case 1 -> size / devid + "kb";
            case 2 -> size / devid + "mb";
            case 3 -> size / devid + "gb";
            default -> size + "";
        };
    }
}
