package cn.iocoder.yudao.module.smartfactory.controller.admin.factorydata;

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.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.smartfactory.controller.admin.factorydata.vo.*;
import cn.iocoder.yudao.module.smartfactory.controller.admin.factorydata.vo.sizeData.FactoryDataSizeCreateReqVO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.factorydata.vo.sizeData.FactoryDataSizeDetailRespVO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.factorydata.vo.sizeData.FactoryDataSizeTotalVO;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.factorydata.FactoryDataSizeDO;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.factoryinfo.FactoryInfoDO;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.size.SizeDO;
import cn.iocoder.yudao.module.smartfactory.service.factorydata.FactoryDataService;
import cn.iocoder.yudao.module.smartfactory.service.factorydata.FactoryDataSizeService;
import cn.iocoder.yudao.module.smartfactory.service.factoryinfo.FactoryInfoService;
import cn.iocoder.yudao.module.smartfactory.service.size.SizeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.text.DecimalFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;

@Tag(name = "管理后台 - 工厂出库入库数据")
@RestController
@RequestMapping("/smartfactory/factory-data")
@Validated
public class FactoryDataController {

    @Resource
    private FactoryDataService dataService;

    @Resource
    private FactoryDataSizeService factoryDataSizeService;

    @Resource
    private FactoryInfoService factoryInfoService;

    @Resource
    private SizeService sizeService;

    @PostMapping("/create-size")
    @Operation(summary = "创建工厂出库入库规格数据")
    @PreAuthorize("@ss.hasPermission('smartfactory:factory-data:create')")
    public CommonResult<Long> createSizeData(@Valid @RequestBody FactoryDataSizeCreateReqVO createReqVO) throws Exception {

        return success(factoryDataSizeService.createData(createReqVO));
    }

    @PutMapping("/update")
    @Operation(summary = "更新工厂出库入库数据")
    @PreAuthorize("@ss.hasPermission('smartfactory:factory-data:update')")
    public CommonResult<Boolean> updateData(@Valid @RequestBody FactoryDataSizeCreateReqVO updateReqVO) throws Exception {

        dataService.updateData(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除工厂出库入库数据")
    @Parameter(name = "factoryId", description = "工厂编号", required = true, example = "1000078")
    @Parameter(name = "date", description = "日期", required = true, example = "2024-05-17")
    @PreAuthorize("@ss.hasPermission('smartfactory:factory-data:delete')")
    public CommonResult<Boolean> deleteData(@RequestParam("factoryId") Long factoryId, @RequestParam("date") String date) {

        dataService.deleteData(factoryId, date);
        return success(true);
    }

    @GetMapping("/getLastSize")
    @Operation(summary = "获得指定工厂上一次录入的规格信息")
    @Parameter(name = "factoryId", description = "工厂编号", required = true, example = "1000078")
    @Parameter(name = "type", description = "出入库类型 | 入库1 出库2", required = true, example = "1")
    @PreAuthorize("@ss.hasPermission('smartfactory:factory-data:query')")
    public CommonResult<List<Long>> getLastSize(@RequestParam("factoryId") Long factoryId, @RequestParam("type") Integer type) {

        List<FactoryDataSizeDO> dataSizeDOS = factoryDataSizeService.getLastSize(factoryId, type == 1 ? Arrays.asList(1,4) : Arrays.asList(2,3));
        return success(convertList(dataSizeDOS, FactoryDataSizeDO::getSizeId));
    }

    @GetMapping("/get")
    @Operation(summary = "获得工厂出库入库数据")
    @Parameter(name = "factoryId", description = "工厂编号", required = true, example = "1000078")
    @Parameter(name = "date", description = "日期", required = true, example = "2024-05-17")
    @PreAuthorize("@ss.hasPermission('smartfactory:factory-data:query')")
    public CommonResult<FactoryDataSizeDetailRespVO> getData(@RequestParam("factoryId") Long factoryId, @RequestParam("date") String date) {

        return success(dataService.getData(factoryId, date));
    }

    @GetMapping("/get-total")
    @Operation(summary = "获得出入库数据总数 | 入库总数、出库总数、破损总数")
    @PreAuthorize("@ss.hasPermission('smartfactory:factory-data:query')")
    public CommonResult<FactoryDataTotalVO> getDataTotal(@Valid FactoryDataPageReqVO pageReqVO) {

        if (pageReqVO.getDateType() != null) {
            // 设置日期
            setDate(pageReqVO);
        }

        // 获取指定工厂指定日期的出入库数据
        FactoryDataTotalVO dataTotalVO = dataService.getDataTotal(pageReqVO.getFactoryId(), pageReqVO.getDate());

        if (pageReqVO.getFactoryId() != null) {

            // 获取全工厂指定日期的总数据
            FactoryDataTotalVO dataTotal = dataService.getDataTotal(null, pageReqVO.getDate());

            DecimalFormat df = new DecimalFormat("#.##"); // 保留两位小数
            if (dataTotal.getInTotal() != 0) {
                // 设置出入库比列
                dataTotalVO.setInPercentage(df.format((double)dataTotalVO.getInTotal() / dataTotal.getInTotal() * 100L) + "%");
            }
            if (dataTotal.getOutTotal() != 0) {
                // 设置出库比例
                dataTotalVO.setOutPercentage(df.format((double)dataTotalVO.getOutTotal() / dataTotal.getOutTotal() * 100L) + "%");
            }
            if (dataTotalVO.getInTotal() != 0 && dataTotalVO.getOutTotal() != 0) {
                // 设置出入库比列
                dataTotalVO.setInOutPercentage(df.format((double)dataTotalVO.getOutTotal() / dataTotalVO.getInTotal() * 100L) + "%");
            }
        }

        return success(dataTotalVO);
    }

    @GetMapping("/get-totalByFactory")
    @Operation(summary = "获得各个工厂出入库数据总数 | 入库总数、出库总数、破损总数")
    @PreAuthorize("@ss.hasPermission('smartfactory:factory-data:query')")
    public CommonResult<List<FactoryDataTotalVO>> getDataTotalByFactory() {

        return success(dataService.getDataTotalByFactory());
    }

    @GetMapping("/getSizeTotalByFactory")
    @Operation(summary = "获得指定工厂指定日期内，出入库规格明细详情")
    @PreAuthorize("@ss.hasPermission('smartfactory:factory-data:query')")
    public CommonResult<List<FactoryDataSizeTotalVO>> getSizeTotalByFactory(@Valid FactoryDataPageReqVO pageReqVO) {

        if (pageReqVO.getDateType() != null) {
            // 设置日期
            setDate(pageReqVO);
        }

        return success(factoryDataSizeService.getSizeTotalByFactory(pageReqVO.getFactoryId(), pageReqVO.getDate()));
    }

    @GetMapping("/page")
    @Operation(summary = "获得工厂出库入库数据分页")
    @PreAuthorize("@ss.hasPermission('smartfactory:factory-data:query')")
    public CommonResult<PageResult<FactoryDataDetailRespVO>> getDataPage(@Valid FactoryDataPageReqVO pageReqVO) {

        PageResult<FactoryDataDetailRespVO> pageResult = dataService.getDataPage(pageReqVO);
        return success(pageResult);
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出工厂出库入库数据 Excel")
    @PreAuthorize("@ss.hasPermission('smartfactory:factory-data:export')")
    @OperateLog(type = EXPORT)
    public void exportDataExcel(@Valid FactoryDataPageReqVO pageReqVO,
              HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<FactoryDataDetailRespVO> list = dataService.getDataPage(pageReqVO).getList();
        List<FactoryDataExportVO> exportVOS = new ArrayList<>();
        for (FactoryDataDetailRespVO respVO : list) {

            exportVOS.addAll(
                    respVO.getItems().stream().map(info -> {
                        FactoryDataExportVO exportVO = BeanUtils.toBean(info, FactoryDataExportVO.class);
                        exportVO.setFactoryName(respVO.getFactoryName());
                        exportVO.setDate(respVO.getDate());
                        exportVO.setInTotalNum(respVO.getInTotalNum());
                        exportVO.setOutTotalNum(respVO.getOutTotalNum());
                        exportVO.setDamageTotalNum(respVO.getDamageNum());
                        return exportVO;
                    }).collect(Collectors.toList()));
        }
        // 导出 Excel
        ExcelUtils.write(response, "工厂出库入库数据.xlsx", "数据", FactoryDataExportVO.class, exportVOS);
    }

    @GetMapping("/get-import-template")
    @Operation(summary = "获得导入模板")
    public void importTemplate(HttpServletResponse response) throws IOException {

        // 获取工厂信息
        List<FactoryInfoDO> factoryInfoDOS = factoryInfoService.getFactoryListByType();
        List<String> factory = convertList(factoryInfoDOS, FactoryInfoDO::getShortName);

        // 获取规格信息
        List<SizeDO> sizeDOS = sizeService.getListSize();
        List<String> size = sizeDOS.stream().map(info -> info.getId() + ":" + info.getName()).collect(Collectors.toList());

        // 输出
        ExcelUtils.write(response, "出入库数据导入模板.xls", "详情",
                FactoryDataImportVO.class, null,
                0, factory,
                2, size);
    }

    @PostMapping("/import")
    @Operation(summary = "导入出入库数据")
    @Parameter(name = "file", description = "Excel 文件", required = true)
    @Parameter(name = "type", description = "出入库类型 | 1入库 2出库", required = true)
    @PreAuthorize("@ss.hasPermission('smartfactory:factory-data:import')")
    public CommonResult<FactoryImportRespVO> importExcel(@RequestParam("file") MultipartFile file,
                                                         @RequestParam("type") Integer type) throws Exception {

        List<FactoryDataImportVO> list = ExcelUtils.read(file, FactoryDataImportVO.class);

        // 过滤空行
        list = list.stream()
                .filter(data -> data.getFactoryName() != null && data.getDate() != null)
                .collect(Collectors.toList());
        return success(dataService.importUserList(list, type));
    }

    public void setDate(FactoryDataPageReqVO pageReqVO) {

        LocalDate today = LocalDate.now();

        // dateType = 1 为昨日数据
        if (pageReqVO.getDateType() == 1) {

            // 设置日期
            pageReqVO.setDate(new LocalDate[]{today.minusDays(1), today.minusDays(1)});
        }
        // dateType = 2 为本周数据
        if (pageReqVO.getDateType() == 2) {

            // 获取本周的周一
            LocalDate startOfWeek = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));

            // 获取本周的周日
            LocalDate endOfWeek = today.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));

            // 设置日期
            pageReqVO.setDate(new LocalDate[]{startOfWeek, endOfWeek});
        }
        // dateType = 3 为本月数据
        if (pageReqVO.getDateType() == 3) {

            // 获取本月的第一天
            LocalDate startOfMonth = today.with(TemporalAdjusters.firstDayOfMonth());

            // 获取本月的最后一天
            LocalDate endOfMonth = today.with(TemporalAdjusters.lastDayOfMonth());

            // 设置日期
            pageReqVO.setDate(new LocalDate[]{startOfMonth, endOfMonth});
        }
    }
}