package com.gci.boot.modules.vehicles.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gci.boot.annotation.permission.DataPermission;
import com.gci.boot.common.log.annotation.AddSysLog;
import com.gci.boot.common.util.MinioUtils;
import com.gci.boot.common.util.StringUtil;
import com.gci.boot.common.util.ValidatorUtil;
import com.gci.boot.common.validated.SaveValidated;
import com.gci.boot.common.validated.UpdateValidated;
import com.gci.boot.common.vo.Result;
import com.gci.boot.constant.CommonConstant;
import com.gci.boot.enums.FileExtension;
import com.gci.boot.exception.GciBootException;
import com.gci.boot.modules.basedata.entity.TbRepairShopArchives;
import com.gci.boot.modules.basedata.service.ITbRepairShopArchivesService;
import com.gci.boot.modules.msg.enums.SenderTypeEnum;
import com.gci.boot.modules.msg.enums.WorkOrderType;
import com.gci.boot.modules.msg.service.MsgPushService;
import com.gci.boot.modules.msg.vo.MsgRedisVO;
import com.gci.boot.modules.projects.entity.Projects;
import com.gci.boot.modules.projects.service.IProjectsService;
import com.gci.boot.modules.system.service.ISysRoleService;
import com.gci.boot.modules.system.service.ISysUserService;
import com.gci.boot.modules.system.vo.LoginUser;
import com.gci.boot.modules.vehicles.entity.TbRepairAssign;
import com.gci.boot.modules.vehicles.entity.TbRepairCheck;
import com.gci.boot.modules.vehicles.entity.TbRepairInfo;
import com.gci.boot.modules.vehicles.mapper.TbRepairInfoMapper;
import com.gci.boot.modules.vehicles.mapper.TbViolationRecordMapper;
import com.gci.boot.modules.vehicles.service.*;
import com.gci.boot.modules.vehicles.vo.*;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Api(tags="维修")
@Slf4j
@RestController
@RequestMapping("/vehicles/repair")
public class RepairController {

    @Autowired
    private ITbRepairAssignService repairAssignService;
    @Autowired
    private ITbRepairCheckService repairCheckService;
    @Autowired
    private ITbRepairInfoService repairInfoService;
    @Autowired
    private ITbRepairOfferService repairOfferService;
    @Autowired
    private TbViolationRecordMapper violationRecordMapper;
    @Autowired
    private TbRepairInfoMapper repairInfoMapper;
    @Autowired
    private IProjectsService projectsService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private MinioUtils minioUtils;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private ISysRoleService sysRoleService;
    @Autowired
    private ITbRepairShopArchivesService tbRepairShopArchivesService;
    @Autowired
    private IRepairUpkeepImportService repairUpkeepImportService;
    @Value("${failExcel}")
    private String failExcel;
    @Autowired
    private MsgPushService msgPushService;

    /**
     * 分页列表查询
     *
     * @param pageNo
     * @param pageSize
     * @param req
     * @return
     */
    @AddSysLog("维修-分页列表查询")
    @GetMapping(value = "/list")
    public Result<?> queryPageList(RepairInfoListVO vo,
                                   @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                   @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                   HttpServletRequest req) {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        //处理司机身份和维修厂身份的过滤：优先司机，不考虑重叠的情况
        Integer departCategory = projectsService.judgeDepartCategory();
        //超级管理员查询全部数据
        if(departCategory != 5){
            //内部员工按项目列表过滤*
            if(departCategory == 1 || departCategory == 4){
                List<String> listProjectStaff = projectsService.queryProjectListOfUser();
                if(CollectionUtils.isNotEmpty(listProjectStaff)){
                    vo.setListProject(listProjectStaff);
                }else {
                    vo.setProjectId("no permission");
                }
            }else if(departCategory == 3){
                if(StringUtils.isNotEmpty(sysUser.getUsername())){
                    vo.setDriverParam(sysUser.getUsername());
                }else {
                    vo.setProjectId("no permission");
                }
            }else if(departCategory == 2){
                List<TbRepairShopArchives> listRepairShop = tbRepairShopArchivesService.getRepairShopByUserId(sysUser.getId());
                List<String> listRepairShopIds = listRepairShop.stream().map(TbRepairShopArchives::getId).collect(Collectors.toList());
                if(CollectionUtils.isNotEmpty(listRepairShopIds)){
                    vo.setListRepairShop(listRepairShopIds);
                }else {
                    vo.setProjectId("no permission");
                }
            }else{
                vo.setProjectId("no permission");
            }
        }
        Page<RepairInfoListVO> page = new Page<RepairInfoListVO>(pageNo, pageSize);
        IPage<RepairInfoListVO> pageList = repairInfoService.getRepairInfoList(page, vo);
        return Result.ok(pageList);
    }


    /**
     * 获取报修信息所属项目下拉列表
     */
    @AddSysLog("维修-获取报修信息所属项目下拉列表")
    @GetMapping(value = "/queryProjects")
    @DataPermission(item="A.projectId", sqlIds = {"com.gci.boot.modules.vehicles.mapper.TbViolationRecordMapper.queryProjects"})
    public Result<?> queryProjects() {
        List<VehicleProjectVO> list = violationRecordMapper.queryProjects(0,0);
        return Result.ok(list);
    }

    /**
     * 获取报修信息车牌号及车辆信息列表
     */
    @AddSysLog("维修-获取报修信息车牌号及车辆信息列表")
    @GetMapping(value = "/queryVehicleInfoByProjectId")
    public Result<?> queryVehicleInfoByProjectId(String projectId) {
        List<VehicleInfoVO> list = repairInfoMapper.findVehicleInfoByProjectId(projectId);
        return Result.ok(list);
    }

    /**
     * 添加
     */
    @AddSysLog("维修-添加编辑维修信息")
    @PostMapping(value = "/addOrEdit")
    public Result<?> add(@RequestBody @Validated(SaveValidated.class) TbRepairInfo tbRepairInfo) {
        Projects projects = projectsService.getById(tbRepairInfo.getProjectId());
        if(Objects.nonNull(projects)){
            tbRepairInfo.setProjectName(projects.getProjectName());
        }
        if(StrUtil.isNotBlank(tbRepairInfo.getId())){
            repairInfoService.updateById(tbRepairInfo);
            return Result.ok("操作成功！");
        }
        tbRepairInfo.setFlowStatus(2);
        tbRepairInfo.setFlowNode(1);
        tbRepairInfo.setAddType(2);
        //报修时间
        if(Objects.isNull(tbRepairInfo.getRepairTime())){
            tbRepairInfo.setRepairTime(new Date());
        }

        //工单号
        String format = DateUtil.format(new Date(),"yyyyMMddHHmmssSSS");
        tbRepairInfo.setOrderNo(format);

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String username = "";
        if(Objects.nonNull(sysUser)){
            username = sysUser.getUsername();
        }
        tbRepairInfo.setCreateBy(username);

        repairInfoService.save(tbRepairInfo);
        //补充节点操作人
        TbRepairCheck repairCheck = new TbRepairCheck();
        repairCheck.setRepairId(tbRepairInfo.getId());
        if(Objects.nonNull(sysUser)){
            repairCheck.setCheckPeople(sysUser.getRealname());
        }
        repairCheck.setCheckTime(new Date());
        repairCheck.setCheckPeopleType("4");
        repairCheckService.save(repairCheck);

        //推送微信消息
        ThreadUtil.execAsync(()->{
            msgPushService.pushMsgToRedis(new MsgRedisVO(
                    SenderTypeEnum.YYWB.getSendType(),tbRepairInfo.getId(),
                    tbRepairInfo.getProjectId(), WorkOrderType.REPAIR.getType(),"待派单",
                    DateUtil.format(new Date(),"yyyy-MM-dd HH:mm:ss"),projects.getProjectName() + "工单更新，请及时查看"));
        });
        return Result.ok("操作成功！");
    }

    /**
     * 编辑
     */
    @AddSysLog("维修-编辑维修信息")
    @PutMapping(value = "/edit")
    public Result<?> edit(@RequestBody @Validated(UpdateValidated.class) TbRepairInfo tbRepairInfo) {
        Projects projects = projectsService.getById(tbRepairInfo.getProjectId());
        if(Objects.nonNull(projects)){
            tbRepairInfo.setProjectName(projects.getProjectName());
        }
        repairInfoService.updateById(tbRepairInfo);
        return Result.ok("编辑成功！");
    }


    /**
     * 删除
     */
    @AddSysLog("维修-删除维修信息")
    @DeleteMapping(value = "/realDelete")
    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
        repairInfoService.removeById(id);
        return Result.ok("删除成功！");
    }

    /**
     * 作废
     */
    @AddSysLog("维修-作废维修信息")
    @PostMapping(value = "/cancel")
    public Result<?> cancel(@RequestBody CancelVO vo) {
        String arg = StringUtil.checkString(vo.getCancelIdea(),200);
        if(StrUtil.isNotBlank(arg)){
            return Result.error(101,"作废原因 " + arg);
        }
        String realName = "";
        if(StrUtil.isNotBlank(vo.getRealname())){
            realName = vo.getRealname();
        }else{
            LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
            if(Objects.nonNull(sysUser)){
                realName = sysUser.getRealname();
            }
        }

        repairInfoService.update(new LambdaUpdateWrapper<TbRepairInfo>().eq(TbRepairInfo::getId,vo.getId())
                .set(TbRepairInfo::getFlowStatus,9)
                .set(TbRepairInfo::getFlowNode,4)
                .set(TbRepairInfo::getCancelIdea,vo.getCancelIdea())
                .set(TbRepairInfo::getCancelPeople,realName)
                .set(TbRepairInfo::getCancelTime,new Date()));
        return Result.ok("作废成功！");
    }

    /**
     * 导出
     * @return
     */
    @AddSysLog("维修-导出维修信息")
    @GetMapping("/export")
    public Result<?> export(RepairInfoListVO vo, HttpServletResponse response){
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        //处理司机身份和维修厂身份的过滤：优先司机，不考虑重叠的情况
        Integer departCategory = projectsService.judgeDepartCategory();
        //超级管理员查询全部数据
        if(departCategory != 5){
            //内部员工按项目列表过滤*
            if(departCategory == 1 || departCategory == 4){
                List<String> listProjectStaff = projectsService.queryProjectListOfUser();
                if(CollectionUtils.isNotEmpty(listProjectStaff)){
                    vo.setListProject(listProjectStaff);
                }else {
                    vo.setProjectId("no permission");
                }
            }else if(departCategory == 3){
                if(StringUtils.isNotEmpty(sysUser.getUsername())){
                    vo.setDriverParam(sysUser.getUsername());
                }else {
                    vo.setProjectId("no permission");
                }
            }else if(departCategory == 2){
                List<TbRepairShopArchives> listRepairShop = tbRepairShopArchivesService.getRepairShopByUserId(sysUser.getId());
                List<String> listRepairShopIds = listRepairShop.stream().map(TbRepairShopArchives::getId).collect(Collectors.toList());
                if(CollectionUtils.isNotEmpty(listRepairShopIds)){
                    vo.setListRepairShop(listRepairShopIds);
                }else {
                    vo.setProjectId("no permission");
                }
            }else{
                vo.setProjectId("no permission");
            }
        }

        try (OutputStream output = response.getOutputStream()){

            String fileName = "车辆维修.xlsx";
            try {
                fileName = URLEncoder.encode(fileName, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ";" + "filename*=utf-8''" + fileName);
            List<RepairInfoListVO> list = repairInfoMapper.findRepairInfoAllList(vo);
            EasyExcel.write(output, RepairInfoListVO.class).sheet("车辆维修").doWrite(list);

        } catch (IOException e) {
            return Result.error("导出错误！");
        }
        return Result.ok();
    }

    /**
     * 根据维修单id获取维修弹窗详情
     */
    @AddSysLog("维修-根据维修单id获取维修弹窗详情")
    @GetMapping(value = "/getRepairObjectById")
    public Result<?> getRepairObjectById(String id) {
        RepairObjectVO vo = repairInfoService.getRepairObjectById(id);
        return Result.ok(vo);
    }

    /**
     * 数据录入
     */
    @AddSysLog("维修-数据录入")
    @PostMapping(value = "/addDataEntry")
    public Result<?> addDataEntry(@RequestBody @Validated(SaveValidated.class) RepairDataEntryVO vo) {
        String result = repairInfoService.addDataEntry(vo,"0");
        if(StrUtil.isNotBlank(result)){
            return Result.error(101,result);
        }else{
            return Result.ok("添加成功！");
        }
    }

    /**
     * 维修单流程提交
     */
    @AddSysLog("维修-维修单流程提交")
    @PostMapping(value = "/submitRepairObject")
    public Result<?> submitRepairObject(@RequestBody @Validated(SaveValidated.class) RepairObjectVO vo, HttpServletRequest request) {

        if(redisTemplate.hasKey(vo.getId()+"_submitRepairObject")){
            return Result.error(101,"该维修单正在被操作中，无法操作，请刷新!");
        }else{
            redisTemplate.opsForValue().set(vo.getId()+"_submitRepairObject", vo.getId(), 10, TimeUnit.SECONDS);
        }
        String result = "";
        try {
            result = repairInfoService.submitRepairObject(vo,request);
        }catch (Exception e){
            e.printStackTrace();
            return Result.error(101,"提交失败：" + e.getMessage());
        }finally {
            redisTemplate.delete(vo.getId()+"_submitRepairObject");
        }
        if(StrUtil.isNotBlank(result)){
            return Result.error(101,result);
        }else{
            return Result.ok("提交成功！");
        }
    }

    /**
     * 获取指派信息维修厂列表
     */
    @AddSysLog("维修-获取指派信息维修厂列表")
    @GetMapping(value = "/getRepairShop")
    public Result<?> getRepairShop(String id) {
        List<TbRepairAssign> list = repairInfoMapper.findRepairShop();
        return Result.ok(list);
    }

    /**
     * 文件上传
     */
    @AddSysLog("维修-文件上传")
    @PostMapping("/fileUpload")
    public Result<?> upload(HttpServletRequest request) {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        MultipartFile file = multipartRequest.getFile("file");
        if (ObjectUtil.isEmpty(file)) {
            return Result.error("请正确上传文件！");
        }
        List<String> fileTypes = new ArrayList<>();
        for(String type:FileExtension.PIC.getNameList()) {
            fileTypes.add(type);
        }
        for(String type:FileExtension.DOC.getNameList()) {
            fileTypes.add(type);
        }
        return Result.ok(minioUtils.uploadFileV2Valid(file, fileTypes));
    }

    /**
     * 导入
     */
    @AddSysLog(value = "维修-导入")
    @PostMapping("/import")
    public Result<?> repairImport(HttpServletRequest request) throws IOException {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest)request;
        MultipartFile file = multipartRequest.getFile("file");
        if(!ValidatorUtil.isExcelFile(file)){
            return Result.error("导入文件必须为excel!");
        }

        try(InputStream input = file.getInputStream()) {
            List<RepairImportVO> list = EasyExcel.read(input).head(RepairImportVO.class).sheet().doReadSync();
            if(CollectionUtils.isEmpty(list) || ValidatorUtil.allFieldsAreNullInList(list)){
                return Result.error("导入车辆维修数据不能为空！请检查导入模板!");
            }
            return repairUpkeepImportService.repairImport(list);
        }catch (IOException e){
            log.error(e.getMessage(), e);
            return Result.error("导入错误！");
        }
    }

    /**
     * 导入错误信息下载
     */
    @AddSysLog(value = "维修-导入错误信息下载")
    @GetMapping("/downFail")
    public Result<?> downFail(HttpServletResponse response,String path) throws IOException {
        // 设置输出的格式
        // 循环取出流中的数据
        String fullPath = failExcel + path;
        try (InputStream stream = ResourceUtil.getStream(fullPath)) {
            response.setCharacterEncoding("utf-8");
            response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("违章信息导入异常数据", "utf-8"));
            response.setContentType("application/x-xls;");
            response.setHeader("content-type", "application/octet-stream");
            byte[] b = new byte[1024 * 10];
            int len;
            while ((len = stream.read(b)) > 0) {
                response.getOutputStream().write(b, 0, len);
            }
            // 下载完成后删除文件
            new Thread(() -> {
                try {
                    //延迟 3 秒,避免文件被占用
                    Thread.sleep(3000);
                    ValidatorUtil.deleteFile(fullPath);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        } catch (IORuntimeException e){
            e.printStackTrace();
            return Result.error("文件不存在!");
        }catch (Exception e) {
            e.printStackTrace();
            return Result.error("导出异常!");
        }
        return Result.ok();
    }

    /**
     * 导入模板下载
     */
    @AddSysLog(value = "维修-导入模板下载")
    @GetMapping("/downTemplate")
    public Result<?> downImport(HttpServletResponse response) throws IOException {
        // 设置输出的格式
        // 循环取出流中的数据
        try (InputStream stream = ResourceUtil.getStream("excelTemplate/车辆维修导入模板.xlsx")) {
            response.setCharacterEncoding("utf-8");
            response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("车辆维修导入模板", "utf-8"));
            response.setContentType("application/x-xls;");
            response.setHeader("content-type", "application/octet-stream");
            byte[] b = new byte[1024 * 10];
            int len;
            while ((len = stream.read(b)) > 0) {
                response.getOutputStream().write(b, 0, len);
            }
        } catch (IORuntimeException e){
            e.printStackTrace();
            return Result.error("文件不存在!");
        }catch (Exception e) {
            e.printStackTrace();
            return Result.error("导出异常!");
        }
        return Result.ok();
    }
}
