package com.youlai.boot.system.service.impl;

import com.youlai.boot.common.constant.SystemConstants;
import com.youlai.boot.common.exception.BusinessException;
import com.youlai.boot.common.result.PageResult;
import com.youlai.boot.common.util.SystemUtil;
import com.youlai.boot.core.security.util.SecurityUtils;
import com.youlai.boot.system.model.entity.DemandFile;
import com.youlai.boot.system.model.form.DirForm;
import com.youlai.boot.system.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.system.mapper.RecordMapper;
import com.youlai.boot.system.model.entity.Record;
import com.youlai.boot.system.model.form.RecordForm;
import com.youlai.boot.system.model.query.RecordQuery;
import com.youlai.boot.system.model.vo.RecordVO;
import com.youlai.boot.system.converter.RecordConverter;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import org.springframework.web.multipart.MultipartFile;

import static com.youlai.boot.common.util.SystemUtil.renameFile;

/**
 * 部署记录服务实现类
 *
 * @author kangyu
 * @since 2024-10-08 14:14
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class RecordServiceImpl extends ServiceImpl<RecordMapper, Record> implements RecordService {


    private final RecordConverter recordConverter;


    private final ConfigService configService;


    private final FolderNodeService folderNodeService;

    private final FTPService ftpService;
    private final SysFolderService sysFolderService;

    /**
     * 获取部署记录分页列表
     *
     * @param queryParams 查询参数
     * @return {@link IPage<RecordVO>} 部署记录分页列表
     */
    @Override
    public IPage<RecordVO> getRecordPage(RecordQuery queryParams) {

//        DirForm dirForm = new DirForm();
//
//        dirForm.setDirId(queryParams.getDirId());
//        dirForm.setPageType(queryParams.getPageType());
//
//        String path = folderNodeService.getPath(dirForm)+File.separator;
//
//        path =  path.replace("\\","\\\\");
//
//        queryParams.setPath(path);

        List<Integer> subIds = sysFolderService.getSubFolderIdsRecursively(queryParams.getFolderId());

        queryParams.setSubIds(subIds);

        return this.baseMapper.getRecordPage(
                new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
                queryParams
        );

    }

    /**
     * 获取部署记录表单数据
     *
     * @param id 部署记录ID
     * @return
     */
    @Override
    public RecordForm getRecordFormData(Long id) {
        Record entity = this.getById(id);
        RecordForm form = recordConverter.toForm(entity);
        form.setId(entity.getId());
        return form;
    }

    /**
     * 新增部署记录
     *
     * @param formData 部署记录表单对象
     * @return
     */
    @Override
    public boolean saveRecord(RecordForm formData) {

        Record entity = recordConverter.toEntity(formData);

        entity.setUserId(SecurityUtils.getUserId());

        entity.setCreateTime(LocalDateTime.now());

        entity.setPath(formData.getPath());

        entity.setStatus("0");

        entity.setUrl(getUrl(entity.getPath()));

        entity.setAuto_delete(0);

        boolean save = this.save(entity);

        ftpService.uploadFile("182.92.126.35",entity.getPath());

        return save;
    }


    String getUrl(String abPath){
        StringBuilder path = new StringBuilder(abPath.replace(configService.getSystemConfig(SystemConstants.UPLOAD_PATH).toString(), ""));
        String[] split = path.toString().split(Matcher.quoteReplacement(File.separator));
        path = new StringBuilder();
        for (String str : split) {
            path.append("/").append(str);
        }
        return configService.getSystemConfig(SystemConstants.VIEW_PREFIX)+ path.toString();
    }

    /**
     * 更新部署记录
     *
     * @param id       部署记录ID
     * @param formData 部署记录表单对象
     * @return
     */
    @Override
    public boolean updateRecord(Long id, RecordForm formData) {
        Record entity = recordConverter.toEntity(formData);
        entity.setId(formData.getId());
        entity.setPath(formData.getPath());
        entity.setUpdateTime(LocalDateTime.now());
        entity.setPath(formData.getPath());
        return this.updateById(entity);
    }

    /**
     * 删除部署记录
     *
     * @param ids 部署记录ID，多个以英文逗号(,)分割
     * @return
     */
    @Override
    public boolean deleteRecords(String ids) {
        Assert.isTrue(StrUtil.isNotBlank(ids), "删除的部署记录数据为空");
        // 逻辑删除
        List<Long> idList = Arrays.stream(ids.split(","))
                .map(Long::parseLong)
                .toList();
        idList.forEach(id -> {
            Record record = baseMapper.selectById(id);
            record.setIsDeleted(1);
            baseMapper.updateById(record);
            try {
                Files.deleteIfExists(Path.of(record.getPath()));

            }catch (Exception e){
                log.error(e.getMessage(),e);
                throw new BusinessException(e.getMessage());
            }


        });


        return true;
    }

    private void deleteFileByRecordId(){

    }

    @Override
    public boolean startJarFile(Long id) {

        String jarPath = configService.getSystemConfig("JAR_PATH").toString();
        String javaPath = configService.getSystemConfig("JAVA_PATH").toString();
        String javaLogPath = configService.getSystemConfig("JAR_LOG_PATH").toString();
        String javaMem = configService.getSystemConfig("JAR_MEM").toString();
        String javaTimeOpts = configService.getSystemConfig("JAVA_TIME_OPTS").toString();
        Record record = this.baseMapper.selectById(id);
        String jarFileName = record.getFileName();
        String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        String jarLogName = jarFileName.replace(".jar", timestamp + ".log");


        String os = System.getProperty("os.name").toLowerCase();
        ProcessBuilder processBuilder = new ProcessBuilder();
        if (os.contains("win")) {
            return false;
        } else if (os.contains("nix") || os.contains("nux") || os.contains("mac")) {

            String startCommand = "nohup " + javaPath + " -server -Xms" + javaMem + " -Xmx" + javaMem + " " + javaTimeOpts + " -jar " + record.getPath() + " > " + javaLogPath + File.separator + jarLogName + " 2>&1 &";
            log.info("exec command {}", startCommand);
            String[] commands = {
                    "/bin/sh", "-c",
                    startCommand
            };
            processBuilder = new ProcessBuilder(commands);
        }
        try {
            Process process = processBuilder.start();

            // 获取命令执行的输入流（标准输出）
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line).append("\n");
            }

            // 等待进程结束并获取退出值
            process.waitFor();
            // 输出命令的结果

            record.setLog(javaLogPath + File.separator + jarLogName);
            this.baseMapper.updateById(record);
            return true;
        } catch (IOException | InterruptedException e) {
            log.error(e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean stopJarFile(Long id) {
        try {
            String jarPath = configService.getSystemConfig("JAR_PATH").toString();
            Record record = this.baseMapper.selectById(id);

            String pidCommand = "ps --no-heading -ef|grep java|grep "
                    + "|grep "
                    + record.getPath()
                    + "|awk '{print $2}'";
            log.info("exec command {}", pidCommand);
            String[] pidCommands = {
                    "/bin/sh", "-c",
                    pidCommand
            };
            Process process = new ProcessBuilder(pidCommands).start();
            process.waitFor();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String pid = reader.readLine();

            if (StringUtils.isNotBlank(pid)) {
                log.info("killed pid is {}", pid);
                String[] killCommands = {
                        "/bin/sh", "-c",
                        "kill -9 "+pid+" > /dev/null 2>&1"
                };
                Process killedProcess =  new ProcessBuilder(killCommands).start();
                killedProcess.waitFor();
            }
            return true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }

    }

    @Override
    public String saveFile(MultipartFile file, String type,int
            dirId) {
        DirForm dirForm = new DirForm();
        dirForm.setPageType(type);
        dirForm.setDirId(dirId);

        String path = folderNodeService.getPath(dirForm);

        String newFileName = renameFile(Objects.requireNonNull(file.getOriginalFilename()));

        File destFile = new File(path, newFileName);

        try (FileOutputStream fos = new FileOutputStream(destFile)) {
            log.info("写入文件 {}",file.getOriginalFilename());
            fos.write(file.getBytes());
            return destFile.getAbsolutePath();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            return "";
        }



    }

    @Override
    public String saveFile(MultipartFile file,String pageType) {
        log.info("接收到文件 {}",file.getName());

        String demandFilePathPrefix = configService.getSystemConfig(pageType).toString();

        String fileName = SystemUtil.renameFile(Objects.requireNonNull(file.getOriginalFilename()));

        String absPath = demandFilePathPrefix + File.separator + fileName;

        File destFile = new File(absPath);

        try (FileOutputStream fos = new FileOutputStream(destFile)) {
            log.info("写入文件 {}",file.getOriginalFilename());
            fos.write(file.getBytes());

            return absPath;
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }


    private File backupExistingFile(File existingFile) {
        String originalFilename = existingFile.getName();
        String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        String backupFilename = originalFilename + "_" + timestamp;
        File backupFile = new File(existingFile.getParent(), backupFilename);

        try {
            Files.copy(Paths.get(existingFile.toURI()), Paths.get(backupFile.toURI()));
        } catch (IOException e) {
            e.printStackTrace();
        }

        return backupFile;
    }

}
