package com.ho.flow.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Snowflake;
import com.alibaba.fastjson.JSONObject;
import com.ho.business.entity.DeviceTypeCol;
import com.ho.business.vo.DeviceTypeList;
import com.ho.business.vo.req.EventColReq;
import com.ho.business.vo.req.MonitorQuery;
import com.ho.business.vo.req.device.DeviceListReq;
import com.ho.common.tools.annotation.TokenIgnore;
import com.ho.common.tools.constant.CommonConstant;
import com.ho.common.tools.constant.ContextConstant;
import com.ho.common.tools.constant.RedisKeyConstant;
import com.ho.common.tools.entity.ProcessOrder;
import com.ho.common.tools.entity.SimpleUser;
import com.ho.common.tools.entity.UserDetailRespVO;
import com.ho.common.tools.entity.WorkOrderPicture;
import com.ho.common.tools.exception.DataResult;
import com.ho.common.tools.util.PageResult;
import com.ho.flow.constant.FlowConstant;
import com.ho.flow.entity.SendSmsConfig;
import com.ho.flow.entity.WorkOrderPlan;
import com.ho.flow.entity.WorkOrderPlanSub;
import com.ho.flow.entity.WorkOrderSub;
import com.ho.flow.entity.process.MovementDTO;
import com.ho.flow.feignclient.BusinessFeignClient;
import com.ho.flow.feignclient.UserFeignClient;
import com.ho.flow.mapper.WorkOrderPlanMapper;
import com.ho.flow.mapper.WorkOrderPlanSubMapper;
import com.ho.flow.mapper.WorkOrderSubMapper;
import com.ho.flow.monitor.EventToProcessMonitor;
import com.ho.flow.service.*;
import com.ho.flow.service.process.service.ProcessFlowNewService;
import com.ho.flow.vo.AlarmConfig;
import com.ho.flow.vo.Event;
import com.ho.flow.vo.req.AlarmConfig.AlarmConfigQueryVo;
import com.ho.flow.vo.req.SendSmsConfig.SendSmsConfigQueryReq;
import com.ho.flow.vo.req.event.*;
import com.ho.flow.vo.resp.StationStatusRespVO;
import com.ho.flow.vo.resp.event.*;
import com.ho.user.api.vo.req.SysSubDictVO;
import com.itextpdf.text.Document;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description 提供给外部调用，不校验token
 * Author yule
 * Date 2023/2/6 10:08
 */
@RestController
@RequestMapping(ContextConstant.FLOW_CONTEXT + "outerApi")
@Api(tags = "测试")
@Slf4j
public class OuterApiController {

    @Autowired
    ProcessFlowService processFlowService;

    @Autowired
    WorkOrderService workOrderService;

    @Autowired
    DeviceColDefineService deviceColDefineService;


    @Autowired
    EventService eventService;

    @Autowired
    WorkOrderPictureService workOrderPictureService;

    @Autowired
    AlarmConfigService alarmConfigService;

    @Autowired
    SendSmsConfigService sendSmsConfigService;

    @Autowired
    FlowOutApiService flowOutApiService;

    @Autowired
    Snowflake snowflake;

    @Autowired
    WorkOrderPlanMapper workOrderPlanMapper;

    @Autowired
    WorkOrderPlanSubMapper workOrderPlanSubMapper;

    @Autowired
    WorkOrderSubMapper workOrderSubMapper;

    @Autowired
    BusinessFeignClient businessFeignClient;

    @Autowired
    UserFeignClient userFeignClient;

    @Autowired
    ProcessFlowNewService processFlowNewService;

    EventToProcessMonitor monitor = new EventToProcessMonitor();

    @Value("${spring.activiti.flag}")
    private Integer flag;

    @Value("${spring.profiles.active}")
    String env;

    @Value("${openRedis.host}")
    String host;

    @Value("${openRedis.port}")
    String port;

    @Value("${openRedis.pass}")
    String pass;

    @Value("${openTestRedis.host}")
    String testHost;

    @Value("${openTestRedis.port}")
    String testPort;

    @Value("${openTestRedis.pass}")
    String testPass;

    //新增告警数据入库
    @PostMapping("addEvents")
    @TokenIgnore
    public DataResult addEvents(@RequestBody EventAddReq eventAddReq) {
        List<EventAddReq> list = new ArrayList<>();
        list.add(eventAddReq);
        DataResult dataResult = flowOutApiService.addEvents(list);
        return dataResult;
    }

    @PostMapping("addEventsList")
    @TokenIgnore
    public DataResult addEventsList(@RequestBody List<EventAddReq> list) {
        flowOutApiService.addEvents(list);
        return DataResult.success();
    }

    //新增图片数据入库
    @PostMapping("/addPicture")
    @TokenIgnore
    public WorkOrderPicture addPicture(@RequestBody String url) {
        WorkOrderPicture picture = workOrderPictureService.insertPicture(url);
        return picture;
    }

    @PostMapping("/selectPictureById")
    @TokenIgnore
    public WorkOrderPicture selectPictureById(@RequestBody Integer id) {
        WorkOrderPicture workOrderPicture = workOrderPictureService.selectById(id);
        return workOrderPicture;
    }

    @PostMapping("/selectWorkOrderByStationId")
    @TokenIgnore
    public DataResult<Integer> selectWorkOrderByStationId(@RequestBody Integer stationId) {
        Integer orderNum = workOrderService.selectByStationId(stationId);
        return DataResult.success(orderNum);
    }

    /**
     * 判断设备是否正常
     *
     * @param alarmConfigQueryVo
     * @return true代表正常，false代表异常
     */
    @PostMapping("/isRecoveryDevice")
    @TokenIgnore
    public Boolean isRecoveryDevice(@RequestBody AlarmConfigQueryVo alarmConfigQueryVo) {
        return flowOutApiService.isRecoveryDevice(alarmConfigQueryVo);
    }

    /**
     * 判断电站是否在正常
     *
     * @param stationStatusReq
     * @return
     */
    @PostMapping("/isNormalStation")
    @TokenIgnore
    public DataResult<List<StationStatusRespVO>> isNormalStation(@RequestBody AlarmConfigQueryVo stationStatusReq) {
        return DataResult.success(flowOutApiService.isNormalStation(stationStatusReq));
    }

    @PostMapping("/selectEventByParams")
    @TokenIgnore
    public Event selectEventByParams(@RequestBody EventQueryReqVO eventQueryReqVO) {
        Event event = new Event();
        event.setStationId(eventQueryReqVO.getStationId());
        event.setTargetDevice(eventQueryReqVO.getTargetDevice());
        event.setSignal(eventQueryReqVO.getSignal());
        return eventService.selectByParams(event);
    }

    @PostMapping("planAddWorkOrder")
    @TokenIgnore
    public void planAddWorkOrder() {
        //查出所有工单计划
        List<WorkOrderPlan> workOrderPlans = workOrderPlanMapper.selectAll();
        //当前时间
        Date now = new Date();
        for (WorkOrderPlan workOrderPlan : workOrderPlans) {
            //获取到生效时间段
            Date effectDate = workOrderPlan.getEffectDate();
            Date expireDate = workOrderPlan.getExpireDate();
            //判断是否在生效时间段类
            try {
                if (effectDate != null && expireDate != null) {
                    //判断是否有在有效时间段
                    boolean flag = DateUtil.isIn(now, effectDate, expireDate);
                    if (flag) {
                        addWorkOrder(workOrderPlan);
                    }
                } else {
                    addWorkOrder(workOrderPlan);
                }
            } catch (Exception e) {
                log.info("工单计划执行失败,失败的工单计划id:{}", workOrderPlan.getId());
            }
        }


    }

    /**
     * 计划新增工单数据
     *
     * @param workOrderPlan 工单计划
     */
    private void addWorkOrder(WorkOrderPlan workOrderPlan) {
        //当前时间
        Date now = new Date();
        if (workOrderPlan.getDateType() != null) {
            //查询计划执行人(所有类型)
            List<WorkOrderPlanSub> workOrderPlanSubs = workOrderPlanSubMapper.selectByPid(workOrderPlan.getId());
            List<String> userIds = workOrderPlanSubs.stream().filter(s -> {
                return CommonConstant.WorkOrderPlanSubType.PERSON.equals(s.getType());
            }).map(WorkOrderPlanSub::getUserId).collect(Collectors.toList());
            //查询出电站以及设备的子表数据
            List<WorkOrderSub> workOrderSubs = workOrderPlanSubs.stream().filter(s -> {
                return !CommonConstant.WorkOrderPlanSubType.PERSON.equals(s.getType());
            }).map(s -> {
                WorkOrderSub workOrderSub = new WorkOrderSub();
                BeanUtils.copyProperties(s, workOrderSub);
                workOrderSub.setSrcId(s.getSrcId().longValue());
                return workOrderSub;
            }).collect(Collectors.toList());
            //对比执行时间是否为当前时间
            //执行周期分为三种(月,周,天)
            if (CommonConstant.MONTH.equals(workOrderPlan.getDateType())) {
                //查询当前月份的号数
                int i = DateUtil.dayOfMonth(now);
                if (i == workOrderPlan.getDay()) {
                    processFlowService.planAddWorkOrder(workOrderPlan, userIds, workOrderSubs);
                }
            } else if (CommonConstant.WEEK.equals(workOrderPlan.getDateType())) {
                //1表示周日，2表示周一
                int i = DateUtil.dayOfWeek(now);
                Integer day = workOrderPlan.getDay();
                if (i == 1) {
                    i = 7;
                    if (i == day) {
                        processFlowService.planAddWorkOrder(workOrderPlan, userIds, workOrderSubs);
                    }
                } else if (i > 1 && i <= 7) {
                    i = i - 1;
                    if (i == day) {
                        processFlowService.planAddWorkOrder(workOrderPlan, userIds, workOrderSubs);
                    }
                }

            } else if (CommonConstant.DAY.equals(workOrderPlan.getDateType())) {
                processFlowService.planAddWorkOrder(workOrderPlan, userIds, workOrderSubs);
            }
        }
    }

    /**
     * 部署工作流
     *
     * @param groupId 集团id
     */
    @PostMapping("deploymentWorkflow")
    @TokenIgnore
    public DataResult deploymentWorkflow(@RequestBody Integer groupId) {
        processFlowService.deploymentWorkflow(groupId);
        return DataResult.success();
    }

    /**
     * 判断电站接入点状态(是否产生告警数据)定时任务
     *
     * @return
     */
    @PostMapping("accessPointEvent")
    @TokenIgnore
    public DataResult accessPointEvent() {
        eventService.accessPointEvent();
        //判断外接电表状态（是否产生告警数据）定时任务
        eventService.outsideEleEvent();
        return DataResult.success();
    }

//    @PostMapping("outsideEleEvent")
//    @TokenIgnore
//    public DataResult outsideEleEvent() {
//        eventService.outsideEleEvent();
//        return DataResult.success();
//    }

    /**
     * 判断告警类型为告警等级(等级为3)定时发生短信任务
     *
     * @return
     */
    @PostMapping("regularlySendNotifications")
    @TokenIgnore
    public DataResult regularlySendNotifications(@RequestBody MonitorQuery monitorQuery) {
        log.info("jobIntegratedCabinet, {}", monitorQuery);
        eventService.regularlySendNotifications(monitorQuery);
        return DataResult.success();
    }

    /**
     * 定时删除图片和文件
     *
     * @return
     */
    @PostMapping("deletedPicture")
    @TokenIgnore
    public DataResult deletedPicture() {
        //查询全部数据
        List<WorkOrderPicture> workOrderPictures = workOrderPictureService.selectAll();
        //筛选未关联的工单号的图片和文件数据
        workOrderPictures = workOrderPictures.stream().filter(s -> {
            return s.getWorkOrderId() == null;
        }).collect(Collectors.toList());
        //工单图片的id
        List<Long> workOrderPictureIds = new ArrayList<>();
        for (WorkOrderPicture workOrderPicture : workOrderPictures) {
            workOrderPictureIds.add(workOrderPicture.getId().longValue());
            //删除在虚拟机中的文件
            File file = new File(workOrderPicture.getUrl());
            file.delete();
        }
        //再删除数据库中的对象
        workOrderPictureService.deletedByIds(workOrderPictureIds);
        return DataResult.success();
    }


    /**
     * 告警存在故障时长
     *
     * @return
     */
    @PostMapping("faultDuration")
    @TokenIgnore
    public DataResult<List<EventDemo>> faultDuration(@RequestBody EventDemoReqVo eventDemoReqVo) {
        //查询全部数据
        List<EventDemo> eventDemoList = eventService.getFaultDuration(eventDemoReqVo);
        return DataResult.success(eventDemoList);
    }

    /**
     * 告警存在故障时长
     *
     * @return
     */
    @PostMapping("faultDurations")
    @TokenIgnore
    public DataResult<List<EventDemo>> faultDurations(@RequestBody EventDemoReqVo eventDemoReqVo) {
        //查询全部数据
        List<EventDemo> eventDemoList = eventService.getFaultDurations(eventDemoReqVo);
        return DataResult.success(eventDemoList);
    }

    /**
     * 对外提供上送数据接口
     *
     * @param vo
     * @return
     */
    @PostMapping("/eventPage")
    @TokenIgnore
    public DataResult<PageResult<ApiEventRespVO>> eventPage(@RequestBody @Valid ApiEventReqVO vo, HttpServletRequest request) {
        Date now = new Date();
        String beginTime = DateUtil.format(DateUtil.offsetMinute(now, -5), CommonConstant.DATE);
        String endTime = DateUtil.format(now, CommonConstant.DATE);
        vo.setStartTime(beginTime);
        vo.setEndTime(endTime);
        PageResult<ApiEventRespVO> list = getEventRespVOPageResult(vo);
        return DataResult.success(list);
    }

    /**
     * 对外提供上送数据接口
     *
     * @param vo
     * @return
     */
    @PostMapping("/hisEventPage")
    @TokenIgnore
    public DataResult<PageResult<ApiEventRespVO>> hisEventPage(@RequestBody @Valid ApiEventReqVO vo, HttpServletRequest request) {
        Date now = new Date();
        String beginTime = DateUtil.format(DateUtil.offsetDay(now, -6), CommonConstant.DATE);
        String endTime = DateUtil.format(now, CommonConstant.DATE);
        vo.setStartTime(beginTime);
        vo.setEndTime(endTime);
        PageResult<ApiEventRespVO> list = getEventRespVOPageResult(vo);
        return DataResult.success(list);
    }

    private PageResult<ApiEventRespVO> getEventRespVOPageResult(ApiEventReqVO vo) {
        SysSubDictVO sysSubDictVO = new SysSubDictVO();
        sysSubDictVO.setType(CommonConstant.PUSH_DATA);
        Map<String, String> sysSubDict = userFeignClient.getSysSubDict(sysSubDictVO);
        Map<Object, Object> hgetall = new HashMap<>();
        String stationId = sysSubDict.get(vo.getApiSecret());
        PageResult<ApiEventRespVO> list = new PageResult<>();
        if (stationId != null) {

            List<Integer> srcIdList = vo.getSrcIdList();
            if (srcIdList != null && !srcIdList.isEmpty()) {
                //虚拟设备
                List<Integer> virtualSrcIdList = srcIdList.stream().filter(i -> i < 0).collect(Collectors.toList());
                //实际设备
                List<Integer> realSrcIdList = srcIdList.stream().filter(i -> i >= 0).collect(Collectors.toList());
                vo.setSrcIdList(realSrcIdList);
                if (virtualSrcIdList.size() > 0) {
                    DeviceListReq deviceListReq = new DeviceListReq();
                    deviceListReq.setStationId(vo.getStationIds().get(0));
                    deviceListReq.setSrcIdList(srcIdList);
                    List<EventColReq> queryEventParamList = businessFeignClient.getQueryEventParam(deviceListReq);
                    if (queryEventParamList.size() > 0) {
                        vo.setSrcIdList(null);
                        vo.setEventColReqList(queryEventParamList);
                    }
                }
            }

            List<Integer> stationIds = new ArrayList<>();
            stationIds.add(Integer.valueOf(stationId));
            vo.setStationIds(stationIds);
            EventReqPageVO eventReqPageVO = new EventReqPageVO();
            BeanUtils.copyProperties(vo, eventReqPageVO);
            String description = vo.getDescription() == null ? vo.getDescription() : vo.getDescription().trim();
            if ("".equals(description)) {
                eventReqPageVO.setDescription(null);
            } else {
                eventReqPageVO.setDescription(description);
            }
            PageResult<EventRespVO> pageResult = eventService.pageEventInfo(eventReqPageVO);
            List<EventRespVO> pageList = pageResult.getList();
            List<ApiEventRespVO> resultList = new ArrayList<>();
            ApiEventRespVO apiEventRespVO = null;
            for (EventRespVO event : pageList) {
                apiEventRespVO = new ApiEventRespVO();
                BeanUtils.copyProperties(event, apiEventRespVO);
                resultList.add(apiEventRespVO);
            }
            list.setPageNum(pageResult.getPageNum());
            list.setPageSize(pageResult.getPageSize());
            list.setTotalPages(pageResult.getTotalPages());
            list.setTotalRows(pageResult.getTotalRows());
            list.setList(resultList);
        }
        return list;
    }

    @PostMapping("/deviceColDefine")
    @ApiOperation(value = "同步数据告警字段定义")
    @TokenIgnore
    public DataResult deviceColDefine(@RequestBody List<DeviceTypeCol> deviceTypeCols) {
        deviceColDefineService.deviceColDefine(deviceTypeCols);
        return DataResult.success();
    }


    @PostMapping("/syncAlarmConfig")
    @ApiOperation(value = "同步数据告警配置")
    @TokenIgnore
    public DataResult syncAlarmConfig(@RequestBody DeviceTypeList deviceTypeList) {
        deviceColDefineService.syncAlarmConfigList(deviceTypeList);
        return DataResult.success();
    }

    /**
     * 取电站告警最后一条离线数据
     *
     * @param stationStatusReq
     * @return
     */
    @PostMapping("/getNotRecovered")
    @TokenIgnore
    public DataResult<Event> getNotRecovered(@RequestBody AlarmConfigQueryVo stationStatusReq) {
        Event event = flowOutApiService.getNotRecovered(stationStatusReq);
        return DataResult.success(event);
    }

    /**
     * 取电站告警发生的次数和已解决
     *
     * @param stationStatusReq
     * @return
     */
    @PostMapping("/alarmDataStatistics")
    @TokenIgnore
    public DataResult<EventTypeAndLevelsReqVO> alarmDataStatistics(@RequestBody AlarmConfigQueryVo stationStatusReq) {
        EventTypeAndLevelsReqVO eventNum = flowOutApiService.getAlarmDataStatistics(stationStatusReq);
        return DataResult.success(eventNum);
    }


    /**
     * 进行发短信
     *
     * @return
     */
    @PostMapping("/getSendSms")
    @TokenIgnore
    public DataResult getSendSms(@RequestBody SendSmsConfigQueryReq vo) {
        sendSmsConfigService.sendSms(vo);
        return DataResult.success();
    }
    /**
     * 根据天统计告警数目
     * @param vo
     * @return
     */
    @PostMapping("/countEventByDay")
    @TokenIgnore
    public List<EventDayNum> countEventByDay(@RequestBody EventReqPageVO vo) {
        List<EventDayNum> eventDayNums = eventService.countEventByDay(vo);
        return eventDayNums;
    }


    /**
     * 手动修改用户信息,同步更新告警短信中用户信息
     * @param vo
     * @return
     */
    @PostMapping("/updateSendSmsUserInfo")
    @TokenIgnore
    public void updateSendSmsUserInfo(@RequestBody SendSmsConfig vo) {
        sendSmsConfigService.updateByUserId(vo);
    }

    @PostMapping("initProcessInstance")
    @TokenIgnore
    public DataResult initProcessInstance(@RequestBody @Valid ProcessOrder processOrder) {

        Integer orderNum = processFlowNewService.initProcessInstance(processOrder);
        DataResult result = new DataResult();
        result.setData(orderNum);
        return result;
    }
}
