package org.matrix.autotest.controller;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.matrix.autotest.utils.PageTools;
import org.matrix.database.entity.ExecutionRecord;
import org.matrix.database.entity.TestJob;
import org.matrix.database.service.IExecutionRecordService;
import org.matrix.database.service.ITestCaseService;
import org.matrix.database.service.ITestDataService;
import org.matrix.database.service.ITestJobService;
import org.matrix.database.vo.CommonResult;
import org.matrix.database.vo.CommonResultObj;
import org.matrix.database.vo.ExecutionRecordVo;
import org.matrix.enums.ExecutionRecType;
import org.matrix.exception.GlobalException;
import org.matrix.socket.enums.TestExecuteType;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.*;

/**
 * @author mry
 */
@CrossOrigin
@RestController
@RequestMapping("/executionRecords")
@Api(tags = "对执行记录execution_record的基本操作")
public class ExecutionRecordController {

    private final IExecutionRecordService executionRecordService;

    final
    ITestJobService testJobService;

    final
    ITestCaseService testCaseService;

    final
    ITestDataService testDataService;

    public ExecutionRecordController(IExecutionRecordService executionRecordService, ITestJobService testJobService, ITestCaseService testCaseService, ITestDataService testDataService) {
        this.executionRecordService = executionRecordService;
        this.testJobService = testJobService;
        this.testCaseService = testCaseService;
        this.testDataService = testDataService;
    }

    /**
     * 分页查询执行记录
     *
     * @param pageSize   每页多少条数据
     * @param pageNum    当前页数
     * @param userId     查询条件：用户ID
     * @param testDataId 查询条件：测试数据ID
     * @param testCaseId 查询条件：测试用例ID
     * @param uniqueKey  查询条件：唯一批次号
     * @param status     查询条件：运行状态
     * @param type       查询条件：执行类型
     * @return 分页查询的结果, 执行记录
     */
    @ApiOperation("分页查询执行记录")
    @GetMapping
    public ResponseEntity<CommonResultObj<Page<ExecutionRecord>>> findPageExecutionRecord(
            @RequestParam(defaultValue = "10") int pageSize,
            @RequestParam(defaultValue = "1") int pageNum,
            Long userId,
            Long testDataId,
            Long testCaseId,
            String uniqueKey,
            ExecutionRecType status,
            TestExecuteType type) {
        Page<ExecutionRecord> results = Optional.of(executionRecordService.page(Page.of(pageNum, pageSize)
                , Wrappers.lambdaQuery(ExecutionRecord.class)
                        .eq(userId != null, ExecutionRecord::getUserId, userId)
                        .eq(testDataId != null, ExecutionRecord::getTestDataId, testDataId)
                        .eq(testCaseId != null, ExecutionRecord::getTestCaseId, testCaseId)
                        .eq(StringUtils.hasLength(uniqueKey), ExecutionRecord::getUniqueKey, uniqueKey)
                        .eq(type != null, ExecutionRecord::getType, type)
        )).orElse(new Page<>());
        PageTools.pageTool(pageSize, pageNum, results);
        return results.getRecords().size() != 0
                ? CommonResult.success(results, "查询成功")
                : CommonResult.failed(results, "查询失败或无数据");
    }

    /**
     * 分页查询执行记录
     *
     * @param userId     查询条件：用户ID
     * @param testDataId 查询条件：测试数据ID
     * @param testCaseId 查询条件：测试用例ID
     * @param uniqueKey  查询条件：唯一批次号
     * @param type       查询条件：执行类型
     * @return 分页查询的结果, 执行记录
     */
    @ApiOperation("列表查询执行记录")
    @GetMapping("/list")
    public ResponseEntity<CommonResultObj<List<ExecutionRecord>>> findListExecutionRecord(
            Long userId,
            Long testDataId,
            Long testCaseId,
            String uniqueKey,
            TestExecuteType type) {
        List<ExecutionRecord> results = getExecutionRecords(userId, testDataId, testCaseId, uniqueKey, type);
        Map<Long, Map<Long, Map<Long, List<String>>>> resultMap = new HashMap<>();
        return results.size() != 0
                ? CommonResult.success(results, "查询成功")
                : CommonResult.failed(results, "查询失败或无数据");
    }

    /**
     * 分页查询执行记录
     *
     * @param userId     查询条件：用户ID
     * @param testDataId 查询条件：测试数据ID
     * @param testCaseId 查询条件：测试用例ID
     * @param uniqueKey  查询条件：唯一批次号
     * @param type       查询条件：执行类型
     * @return 分页查询的结果, 执行记录
     */
    @ApiOperation("树状查询执行记录")
    @GetMapping("/tree")
    public ResponseEntity<CommonResultObj<Map<Long, Map<Long, Map<Long, List<ExecutionRecordVo>>>>>> tree(
            Long userId,
            Long testDataId,
            Long testCaseId,
            String uniqueKey,
            TestExecuteType type) {
        List<ExecutionRecord> results = getExecutionRecords(userId, testDataId, testCaseId, uniqueKey, type);
        List<ExecutionRecordVo> list = new ArrayList<>();
        for (ExecutionRecord result : results) {
            ExecutionRecordVo recordVo = new ExecutionRecordVo();
            BeanUtils.copyProperties(result,recordVo);
            recordVo.setJobName(testJobService.getById(result.getTestJobId()).getName());
            recordVo.setCaseName(testCaseService.getById(result.getTestCaseId()).getName());
            if (recordVo.getTestDataId()!=-1L){
                recordVo.setDataName(testDataService.getById(result.getTestDataId()).getName());
            }
            list.add(recordVo);
        }
        Map<Long, Map<Long, Map<Long, List<ExecutionRecordVo>>>> map = list.stream().collect(
                groupingBy(ExecutionRecord::getTestJobId,
                        groupingBy(ExecutionRecord::getTestCaseId,
                                groupingBy(ExecutionRecord::getTestDataId))));
        return  CommonResult.success(map, "查询成功");
    }


    private List<ExecutionRecord> getExecutionRecords(Long userId, Long testDataId, Long testCaseId, String uniqueKey, TestExecuteType type) {
        List<ExecutionRecord> results = Optional.of(executionRecordService.list(
                Wrappers.lambdaQuery(ExecutionRecord.class)
                        .eq(userId != null, ExecutionRecord::getUserId, userId)
                        .eq(testDataId != null, ExecutionRecord::getTestDataId, testDataId)
                        .eq(testCaseId != null, ExecutionRecord::getTestCaseId, testCaseId)
                        .eq(StringUtils.hasLength(uniqueKey), ExecutionRecord::getUniqueKey, uniqueKey)
                        .eq(type != null, ExecutionRecord::getType, type)
        )).orElseThrow(() -> new GlobalException("xxx"));
        return results;
    }


    /**
     * 添加执行记录
     *
     * @param executionRecord 执行记录对象
     * @return 添加的执行记录, 以及是否添加成功的提示信息
     */
    @ApiOperation("添加执行记录")
    @PostMapping
    public ResponseEntity<CommonResultObj<ExecutionRecord>> insertExecutionRecord(@RequestBody ExecutionRecord executionRecord) {
        return CommonResult.pred(executionRecordService::save, executionRecord
                , "添加成功", "添加失败");
    }

    /**
     * 修改执行记录
     *
     * @param executionRecord 执行记录对象
     * @return 修改的执行记录, 以及是否修改成功的提示信息
     */
    @ApiOperation("修改执行记录")
    @PutMapping
    public ResponseEntity<CommonResultObj<ExecutionRecord>> updateExecutionRecord(@RequestBody ExecutionRecord executionRecord) {
        return CommonResult.pred(executionRecordService::updateById, executionRecord
                , "修改成功", "修改失败");
    }

    /**
     * 根据之间id删除执行记录
     *
     * @param id 执行记录id
     * @return 删除的环境id, 以及是否删除成功的提示信息
     */
    @ApiOperation("根据主键id删除执行记录")
    @DeleteMapping("/{id}")
    public ResponseEntity<CommonResultObj<Long>> deleteExecutionRecord(@PathVariable Long id) {
        return CommonResult.pred(executionRecordService::removeById, id
                , "删除成功", "删除失败或id不存在");
    }
}
