package cn.iocoder.yudao.module.pms.controller.admin.stat;

import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.pms.controller.admin.inspect.order.vo.IotInspectOrderPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.inspect.order.vo.IotInspectOrderRespVO;
import cn.iocoder.yudao.module.pms.controller.admin.inspect.order.vo.IotReportInspectOrderRespVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.maintain.vo.IotMaintainPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.stat.vo.ReportCost;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
import cn.iocoder.yudao.module.pms.dal.mysql.maintain.IotMaintainMapper;
import cn.iocoder.yudao.module.pms.service.iotmainworkorder.IotMainWorkOrderService;
import cn.iocoder.yudao.module.pms.service.maintain.IotMaintainService;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import com.google.common.collect.ImmutableMap;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;

import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

@Tag(name = "报表维修接口")
@RestController
@RequestMapping("/rq/report/repair")
@Validated
@PermitAll
@AllArgsConstructor
public class IotRepairController {

    private final IotMaintainMapper iotMaintainMapper;
    private final DeptUtil deptUtil;
    private final DeptService deptService;
    private final IotMaintainService iotMaintainService;
    private final IotMainWorkOrderService iotMainWorkOrderService;

    @GetMapping("/fee")
    public CommonResult<ImmutableMap<String, Object>> getRepairFee(@Valid IotMaintainPageReqVO pageReqVO) {
        LocalDateTime startTime = pageReqVO.getCreateTime()[0];
        LocalDateTime endTime = pageReqVO.getCreateTime()[1];
        Set<Long> ids;
        if (Objects.isNull(pageReqVO.getDeptId())){
            Long loginUserDeptId = SecurityFrameworkUtils.getLoginUserDeptId();
            String companyCode = deptUtil.getCompanyCode(loginUserDeptId);
            ids = deptUtil.getDeptIds(companyCode);
        } else {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        pageReqVO.setDeptIds(ids);
        BigDecimal totalFee = iotMaintainMapper.getMaintainFeeIn(pageReqVO);
        pageReqVO.setType("out");
        BigDecimal outFee = iotMaintainMapper.getMaintainFee(pageReqVO);
        // 同比 去年同期相同统计数据对比 无数据
        IotMainWorkOrderPageReqVO workOrderReqVO = new IotMainWorkOrderPageReqVO();
        workOrderReqVO.setDeptIds(ids);
        workOrderReqVO.setCreateTime(pageReqVO.getCreateTime());
        List<IotMainWorkOrderDO> workOrders = iotMainWorkOrderService.workOrders(workOrderReqVO);
        BigDecimal byFee = workOrders.stream()
                .map(IotMainWorkOrderDO::getCost)
                .map(fee -> Objects.isNull(fee) ? BigDecimal.ZERO : fee)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal tbByFee = new BigDecimal("0");
        BigDecimal hbByFee = new BigDecimal("0");
        // 同比 去年同期相同统计数据对比 无数据
        tbByFee = tbByFee==null?BigDecimal.ZERO:tbByFee;
        //获取环比
        LocalDateTime lastYearStart = pageReqVO.getCreateTime()[0].minusYears(1);
        LocalDateTime lastYearEnd = pageReqVO.getCreateTime()[1].minusYears(1);
        LocalDateTime[] createTime = pageReqVO.getCreateTime();
        createTime[0] = lastYearStart;
        createTime[1] = lastYearEnd;
        pageReqVO.setCreateTime(createTime);
        pageReqVO.setType(pageReqVO.getType());
        BigDecimal hbTotalFee;
        BigDecimal hbOutFee;
        hbTotalFee = iotMaintainMapper.getMaintainFeeIn(pageReqVO);
        pageReqVO.setType("out");
        hbOutFee = iotMaintainMapper.getMaintainFee(pageReqVO);

        workOrderReqVO.setDeptIds(ids);
        workOrderReqVO.setCreateTime(createTime);
        List<IotMainWorkOrderDO> tbWorkOrders = iotMainWorkOrderService.workOrders(workOrderReqVO);
        tbByFee = tbWorkOrders.stream()
                .map(IotMainWorkOrderDO::getCost)
                .map(fee -> Objects.isNull(fee) ? BigDecimal.ZERO : fee)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal tbTotalFee = new BigDecimal("0");
        BigDecimal tbOutFee = new BigDecimal("0");
        //获取同比
        if ("year".equals(pageReqVO.getTimeType())){
            tbTotalFee = hbTotalFee==null?BigDecimal.ZERO:hbTotalFee;
            tbOutFee = hbOutFee==null?BigDecimal.ZERO:hbOutFee;
            // 环比 当年所有数据 与 去年所有数据 比较
            int currentYear = startTime.getYear();
            int lastYear = currentYear - 1;
            workOrderReqVO.setDeptIds(ids);
            workOrderReqVO.setCreateTime(null);
            // 查询当前所选时间年份的数据
            workOrderReqVO.setYear(currentYear);
            List<IotMainWorkOrderDO> hbCurrentWorkOrders = iotMainWorkOrderService.workOrders(workOrderReqVO);
            byFee = hbCurrentWorkOrders.stream()
                    .map(IotMainWorkOrderDO::getCost)
                    .map(fee -> Objects.isNull(fee) ? BigDecimal.ZERO : fee)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            // 查询当前所选时间年份上一年的保养数据
            workOrderReqVO.setYear(lastYear);
            List<IotMainWorkOrderDO> hbLastWorkOrders = iotMainWorkOrderService.workOrders(workOrderReqVO);
            hbByFee = hbLastWorkOrders.stream()
                    .map(IotMainWorkOrderDO::getCost)
                    .map(fee -> Objects.isNull(fee) ? BigDecimal.ZERO : fee)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            // 按照年的同比数据 比较整年数据
            tbByFee = hbByFee;

        } else if ("month".equals(pageReqVO.getTimeType())) {
            LocalDateTime lastMonthStart = startTime.minusMonths(1);
            LocalDateTime lastMonthEnd = endTime.minusMonths(1);
            LocalDateTime[] monthTime = pageReqVO.getCreateTime();
            monthTime[0] = lastMonthStart;
            monthTime[1] = lastMonthEnd;
            pageReqVO.setCreateTime(monthTime);
            pageReqVO.setType(pageReqVO.getType());
            tbTotalFee = iotMaintainMapper.getMaintainFeeIn(pageReqVO);
            pageReqVO.setType("out");
            tbOutFee = iotMaintainMapper.getMaintainFee(pageReqVO);
            // 保养
            workOrderReqVO.setCreateTime(monthTime);
            List<IotMainWorkOrderDO> monthWorkOrders = iotMainWorkOrderService.workOrders(workOrderReqVO);
            hbByFee = monthWorkOrders.stream()
                    .map(IotMainWorkOrderDO::getCost)
                    .map(fee -> Objects.isNull(fee) ? BigDecimal.ZERO : fee)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        } else if ("day".equals(pageReqVO.getTimeType())) {
            LocalDateTime lastDayStart = startTime.minusDays(1);
            LocalDateTime lastDayEnd = endTime.minusDays(1);
            LocalDateTime[] dayTime = pageReqVO.getCreateTime();
            dayTime[0] = lastDayStart;
            dayTime[1] = lastDayEnd;
            pageReqVO.setCreateTime(dayTime);
            pageReqVO.setType(pageReqVO.getType());
            tbTotalFee = iotMaintainMapper.getMaintainFeeIn(pageReqVO);
            pageReqVO.setType("out");
            tbOutFee = iotMaintainMapper.getMaintainFee(pageReqVO);
            // 保养
            workOrderReqVO.setCreateTime(dayTime);
            List<IotMainWorkOrderDO> dayWorkOrders = iotMainWorkOrderService.workOrders(workOrderReqVO);
            hbByFee = dayWorkOrders.stream()
                    .map(IotMainWorkOrderDO::getCost)
                    .map(fee -> Objects.isNull(fee) ? BigDecimal.ZERO : fee)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }
        // 查询保养费用
        Map<String, Object> byMap = new HashMap<>();
        byMap.put("total", byFee);
        byMap.put("hb", hbByFee == null || (hbByFee.compareTo(BigDecimal.ZERO)==0) ? hbByFee :((byFee.subtract(hbByFee)).divide(hbByFee,2, RoundingMode.HALF_UP)));
        byMap.put("tb", tbByFee==null||(tbByFee.compareTo(BigDecimal.ZERO)==0)?tbByFee:((byFee.subtract(tbByFee)).divide(tbByFee,2, RoundingMode.HALF_UP)));

        Map<String, Object> totalMap = new HashMap<>();
        totalMap.put("total", totalFee);
        totalMap.put("hb", hbTotalFee==null|| hbTotalFee.equals(BigDecimal.ZERO) ? hbTotalFee :((totalFee.subtract(hbTotalFee)).divide(hbTotalFee,2, RoundingMode.HALF_UP)));
        totalMap.put("tb", tbTotalFee==null||tbTotalFee.equals(BigDecimal.ZERO)?tbTotalFee:((totalFee.subtract(tbTotalFee)).divide(tbTotalFee,2, RoundingMode.HALF_UP)));
        Map<String, Object> outMap = new HashMap<>();
        outMap.put("total", outFee);
        outMap.put("hb", hbOutFee==null||hbOutFee.equals(BigDecimal.ZERO)?hbOutFee:((outFee.subtract(hbOutFee)).divide(hbOutFee,2, RoundingMode.HALF_UP)));
        outMap.put("tb", tbOutFee==null||tbOutFee.equals(BigDecimal.ZERO)?tbOutFee:((outFee.subtract(tbOutFee)).divide(tbOutFee,2, RoundingMode.HALF_UP)));
        return CommonResult.success(ImmutableMap.of("repair", totalMap,
                "out", outMap, "byFee", byMap));
    }


    @GetMapping("/page")
    public CommonResult<PageResult<ReportCost>> getOrderFeePage(@Valid IotMaintainPageReqVO pageReqVO) {
        Set<Long> ids;
        if (Objects.isNull(pageReqVO.getDeptId())){
            Long loginUserDeptId = SecurityFrameworkUtils.getLoginUserDeptId();
            String companyCode = deptUtil.getCompanyCode(loginUserDeptId);
            ids = deptUtil.getDeptIds(companyCode);
        } else {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }
        pageReqVO.setDeptIds(ids);
        PageResult<ReportCost> page = iotMaintainService.getReportCost(pageReqVO);
        return success(page);
    }


    @GetMapping("/report/export-excel")
    @Operation(summary = "运维成本导出 Excel")
    @ApiAccessLog(operateType = EXPORT)
    public void exportReport(@Valid IotMaintainPageReqVO pageReqVO,
                             HttpServletResponse response) throws IOException {
        Set<Long> ids;
        if (Objects.isNull(pageReqVO.getDeptId())){
            Long loginUserDeptId = SecurityFrameworkUtils.getLoginUserDeptId();
            String companyCode = deptUtil.getCompanyCode(loginUserDeptId);
            ids = deptUtil.getDeptIds(companyCode);
        } else {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }
        pageReqVO.setDeptIds(ids);
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        PageResult<ReportCost> page = iotMaintainService.getReportCost(pageReqVO);
        // 导出 Excel
        ExcelUtils.write(response, "运维成本统计.xls", "数据", ReportCost.class, page.getList());
    }
}
