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.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.common.log.annotation.AddSysLog;
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.vo.Result;
import com.gci.boot.constant.CommonConstant;
import com.gci.boot.modules.basedata.entity.TbRepairShopArchives;
import com.gci.boot.modules.basedata.service.ITbRepairShopArchivesService;
import com.gci.boot.modules.gis.entity.TbGisRunningbus;
import com.gci.boot.modules.gis.service.ITbGisRunningbusService;
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.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.TbUpkeepBill;
import com.gci.boot.modules.vehicles.entity.TbUpkeepPlan;
import com.gci.boot.modules.vehicles.service.IRepairUpkeepImportService;
import com.gci.boot.modules.vehicles.service.ITbUpkeepBillService;
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.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 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.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/upkeepBill")
public class UpKeepBillController {

    @Autowired
    private ITbUpkeepBillService upkeepBillService;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ITbGisRunningbusService gisRunningbusService;
    @Autowired
    private ISysRoleService sysRoleService;
    @Autowired
    private ITbRepairShopArchivesService tbRepairShopArchivesService;
    @Autowired
    private IProjectsService projectsService;
    @Autowired
    private IRepairUpkeepImportService repairUpkeepImportService;
    @Value("${failExcel}")
    private String failExcel;
    @Autowired
    private MsgPushService msgPushService;

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

    /**
     * 分页列表查询
     *
     * @param pageNo
     * @param pageSize
     * @param req
     * @return
     */
    @AddSysLog("保养台账-分页列表查询")
    @GetMapping(value = "/list")
    public Result<?> queryPageList(UpkeepInfoListVO 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 == 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<UpkeepInfoListVO> page = new Page<UpkeepInfoListVO>(pageNo, pageSize);
        IPage<UpkeepInfoListVO> pageList = upkeepBillService.getUpkeepBillList(page, vo);
        return Result.ok(pageList);
    }

    /**
     * 导出
     * @return
     */
    @AddSysLog("保养台账-导出")
    @GetMapping("/export")
    public Result<?> export(UpkeepInfoListVO 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 == 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<UpkeepInfoListVO> list = upkeepBillService.getAllUpkeepBillList(vo);
            EasyExcel.write(output, UpkeepInfoListVO.class).sheet("保养台账").doWrite(list);

        } catch (IOException e) {
            return Result.error("导出错误！");
        }
        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();
            }
        }
        //查当前总里程
        TbUpkeepBill tbUpkeepBill = upkeepBillService.getById(vo.getId());
        LambdaQueryWrapper<TbGisRunningbus> busQuery = new LambdaQueryWrapper<>();
        busQuery.eq(TbGisRunningbus::getPlateNumber,tbUpkeepBill.getPlateNumber()).last(" limit 1 ");
        upkeepBillService.update(new LambdaUpdateWrapper<TbUpkeepBill>().eq(TbUpkeepBill::getId,vo.getId())
                .set(TbUpkeepBill::getFlowStatus,9)
                .set(TbUpkeepBill::getFlowNode,4)
                .set(TbUpkeepBill::getCancelIdea,vo.getCancelIdea())
                .set(TbUpkeepBill::getCancelPeople,realName)
                .set(TbUpkeepBill::getCancelTime,new Date()));
        return Result.ok("作废成功！");
    }

    /**
     * 根据保养单id获取保养弹窗详情
     */
    @AddSysLog("保养台账-根据保养单id获取保养弹窗详情")
    @GetMapping(value = "/getUpkeepObjectById")
    public Result<?> getUpkeepObjectById(String id) {
        UpkeepObjectVO vo = upkeepBillService.getUpkeepObjectById(id);
        return Result.ok(vo);
    }

    /**
     * 保养台账流程提交
     */
    @AddSysLog("保养台账-保养台账流程提交")
    @PostMapping(value = "/submitUpkeepObject")
    public Result<?> submitUpkeepObject(@RequestBody @Validated(SaveValidated.class) UpkeepObjectVO vo, HttpServletRequest request) {

        if(redisTemplate.hasKey(vo.getId()+"_submitRepairObject")){
            return Result.error(101,"该保养单正在被操作中，无法操作，请刷新!");
        }else{
            redisTemplate.opsForValue().set(vo.getId()+"_submitUpkeepObject", vo.getId(), 10, TimeUnit.SECONDS);
        }

        String result = "";
        try {
            result = upkeepBillService.submitUpkeepObject(vo,request);
        }catch (Exception e){
            e.printStackTrace();
            return Result.error(101,"提交失败：" + e.getMessage());
        }finally {
            redisTemplate.delete(vo.getId()+"_submitUpkeepObject");
        }
        if(StrUtil.isNotBlank(result)){
            return Result.error(101,result);
        }
        return Result.ok("提交成功！");
    }

    /**
     * 导入
     */
    @AddSysLog(value = "保养-导入")
    @PostMapping("/import")
    public Result<?> upkeepImport(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<UpkeepImportVO> list = EasyExcel.read(input).head(UpkeepImportVO.class).sheet().doReadSync();
            if(CollectionUtils.isEmpty(list) || ValidatorUtil.allFieldsAreNullInList(list)){
                return Result.error("导入保养台账数据不能为空！请检查导入模板!");
            }
            return repairUpkeepImportService.upkeepImport(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();
    }
}
