package com.dtok.api.controller;

import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.lang.generator.UUIDGenerator;
import com.dtok.entity.Account;
import com.dtok.entity.LoginHistory;
import com.dtok.entity.Script;
import com.dtok.entity.ScriptHistory;
import com.dtok.entity.params.ScriptFormData;
import com.dtok.framework.base.BaseController;
import com.dtok.framework.exception.BizExceptionEnum;
import com.dtok.framework.response.ResponseData;
import com.dtok.framework.util.ToolUtil;
import com.dtok.framework.util.UploadUtils;
import com.dtok.repository.ScriptHistoryRepository;
import com.dtok.repository.ScriptRepository;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.Transient;
import javax.persistence.criteria.Predicate;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

@RestController
@RequestMapping("/script")
@SaCheckRole(Account.FINAL_ROLE)
public class ScriptController extends BaseController {

    @Autowired
    ScriptRepository scriptRepository;


    @Autowired
    ScriptHistoryRepository scriptHistoryRepository;


    @GetMapping("/search")
    public ResponseData search(@RequestParam("app") String app, @RequestParam("module") String module) {
        Specification<Script> query = (root, query1, criteriaBuilder) -> {
            Predicate predicate = criteriaBuilder.conjunction();
            if (ToolUtil.isNotEmpty(app)) {
                predicate.getExpressions().add(criteriaBuilder.or(criteriaBuilder.like(root.get("app"), app)));
            }
            if (ToolUtil.isNotEmpty(module)) {
                predicate.getExpressions().add(criteriaBuilder.or(criteriaBuilder.like(root.get("module"), module)));
            }
            return predicate;
        };
        List<Script> result = scriptRepository.findAll(query);
        return ResponseData.success(result);
    }

    @GetMapping("/getScript/{id}")
    public ResponseData getScript(@PathVariable String id) {
        return ResponseData.success(scriptRepository.findFirstByUuid(id));
    }

    @PostMapping("/add")
    public ResponseData add(ScriptFormData scriptFormData) throws IOException {
        if (Objects.isNull(scriptFormData.getFile())) {
            throw new NullPointerException("文件不能为空");
        }
        if (!StringUtils.hasLength(scriptFormData.getModule())) {
            throw new NullPointerException("模块不能为空");
        }
        if (!StringUtils.hasLength(scriptFormData.getGroupName())) {
            throw new NullPointerException("组不能为空");
        }
        if (!StringUtils.hasLength(scriptFormData.getApp())) {
            throw new NullPointerException("APP不能为空");
        }
        MultipartFile multipartFile = scriptFormData.getFile();
        InputStream inputStream = multipartFile.getInputStream();
        Path filepath = Paths.get(UploadUtils.getExcelDirFile(), multipartFile.getOriginalFilename());
        try (OutputStream os = Files.newOutputStream(filepath)) {
            os.write(multipartFile.getBytes());
        }
        File file = new File(filepath.toUri());
        FileReader fileReader = new FileReader(file);
        scriptFormData.setScriptContent(fileReader.readString());
        file.delete();
        Script script = new Script();
        BeanUtils.copyProperties(scriptFormData, script);
        script.setUuid(new UUIDGenerator().next());
        script.setCreatedTime(new Date());
        script.setCallCount(0L);
        script.setVersion(1000L);
        scriptRepository.save(script);
        return ResponseData.success("添加成功");
    }

    @PostMapping("/update/{id}")
    public ResponseData update(Script scriptFormData, @PathVariable String id) throws IOException {
        if (!StringUtils.hasLength(scriptFormData.getModule())) {
            throw new NullPointerException("模块不能为空");
        }
        if (!StringUtils.hasLength(scriptFormData.getGroupName())) {
            throw new NullPointerException("组不能为空");
        }
        if (!StringUtils.hasLength(scriptFormData.getApp())) {
            throw new NullPointerException("APP不能为空");
        }
        Script script = scriptRepository.findFirstByUuid(id);
        if (Objects.isNull(script)) {
            throw new NullPointerException(BizExceptionEnum.FILE_NOT_FOUND.getMessage());
        }
        script.setApp(scriptFormData.getApp());
        script.setModule(scriptFormData.getModule());
        script.setGroupName(scriptFormData.getGroupName());
        script.setEncrypt(scriptFormData.getEncrypt());
        scriptRepository.save(script);
        return ResponseData.success("添加成功");
    }


    @GetMapping("/getAllVersionHistoryById/{id}")
    public ResponseData getAllVersionHistoryById(@PathVariable String id) {
        return ResponseData.success(scriptHistoryRepository.searchAllByScriptId(id));
    }

    @GetMapping("/getVersionHistoryById/{id}")
    public ResponseData getVersionHistoryById(@PathVariable String id) {
        return ResponseData.success(scriptHistoryRepository.findFirstByScriptId(id));
    }


    @PostMapping("/versionChange/{id}")
    @Transactional(rollbackFor = Exception.class)
    public ResponseData versionChange(String scriptContent, @PathVariable String id) {
        if (!StringUtils.hasLength(scriptContent)) {
            throw new NullPointerException("内容不能为空");
        }
        Script script = scriptRepository.findFirstByUuid(id);
        if (Objects.isNull(script)) {
            throw new NullPointerException("没有找到脚本");
        }
        ScriptHistory scriptHistory = new ScriptHistory();
        scriptHistory.setApp(script.getApp());
        scriptHistory.setVersion(script.getVersion());
        scriptHistory.setCreatedAt(new Date());
        scriptHistory.setScriptId(script.getUuid());
        scriptHistory.setScriptContent(script.getScriptContent());

        script.setVersion(script.getVersion() + 1L);
        script.setScriptContent(scriptContent);

        scriptHistoryRepository.save(scriptHistory);
        scriptRepository.save(script);

        return ResponseData.success("变更完成");
    }

    @DeleteMapping("/delete/{id}")
    @Transactional(rollbackFor = Exception.class)
    public ResponseData delete(@PathVariable String id) {
        Script script = scriptRepository.findFirstByUuid(id);
        if (Objects.isNull(script)) {
            throw new NullPointerException("没有找到脚本");
        }

        scriptHistoryRepository.deleteAllByScriptId(id);
        scriptRepository.deleteById(id);

        return ResponseData.success("删除成功");
    }

}
