package com.xy.service;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yitter.idgen.YitIdHelper;
import com.xy.collections.list.JArrayList;
import com.xy.collections.list.JList;
import com.xy.config.DeviceThreadPoolConfig;
import com.xy.config.FileConfig;
import com.xy.dto.DeviceSimChargeDto;
import com.xy.dto.OrderMercManageDto;
import com.xy.dto.be.MercDto;
import com.xy.entity.DeviceSimCharge;
import com.xy.mapper.DeviceSimChargeMapper;
import com.xy.service.be.MercService;
import com.xy.util.ExcelUtils;
import com.xy.utils.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.experimental.Accessors;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;

import static com.xy.utils.Beans.copy;
import static com.xy.utils.PlusBeans.toIPage;
import static com.xy.utils.PlusBeans.toPageBean;


/**
 * <p>
 * 设备流量卡充值表 服务实现类
 * </p>
 *
 * @author lijin
 * @since 2023-10-16
 */
@Service
@AllArgsConstructor
@Api(tags = "设备流量卡充值表")
public class DeviceSimChargeServiceImpl extends ServiceImpl<DeviceSimChargeMapper, DeviceSimCharge> implements DeviceSimChargeService {

    private OrderMercManageService orderMercManageService;

    private MercService mercService;

    private DeviceChargingHistoryServiceImpl deviceChargingHistoryService;

    private HttpServletResponse response;

    private FileConfig fileConfig;

    @PostMapping("page")
    @ApiOperation("分页查询")
    public R<PageBean<DeviceSimChargeDto.Vo>> page(@RequestBody DeviceSimChargeDto.Page page) {
        PageBean pageBean = page.getPage();
        LambdaQueryWrapper<DeviceSimCharge> lambdaQueryWrapper = new MybatisPlusQuery().eqWrapper(page, DeviceSimCharge.class)
                .ge(DeviceSimCharge::getCreateTime, page.getBeginCreateTime())
                .le(DeviceSimCharge::getCreateTime, page.getEndCreateTime())
                .build()
                .orderByDesc(!Emptys.check(pageBean.getOrders()), DeviceSimCharge::getCreateTime);
        IPage<DeviceSimCharge> iPage = page(toIPage(pageBean), lambdaQueryWrapper);
        PageBean<DeviceSimChargeDto.Vo> voPageBean = toPageBean(DeviceSimChargeDto.Vo.class, iPage);
        List<DeviceSimChargeDto.Vo> records = voPageBean.getRecords();
        if (Emptys.check(records)) {
            copy(records)
                    .target(() -> orderMercManageService.list(new OrderMercManageDto.SelectList().setId(new JArrayList<>(records).getProperty(DeviceSimChargeDto.Vo::getOrderId))).getData()
                            , DeviceSimChargeDto.Vo::getOrderId, DeviceSimChargeDto.Vo::getFiles, OrderMercManageDto.Vo::getId, OrderMercManageDto.Vo::getFiles
                    ).target(() -> mercService.list(new MercDto.SelectList().setMercIds(new JArrayList<>(records).getProperty(DeviceSimChargeDto.Vo::getMercId).comparing())).getData()
                    , DeviceSimChargeDto.Vo::getMercId, DeviceSimChargeDto.Vo::getMercName, MercDto.Vo::getId, MercDto.Vo::getName)
                    .builder();
        }
        return R.ok(voPageBean);
    }

    @ApiOperation("月统计分页")
    @PostMapping("moonCountPage")
    public R<PageBean<DeviceSimChargeDto.MoonCountVo>> moonCountPage(@RequestBody DeviceSimChargeDto.MoonCountPage moonCountPage) {
        JList<DeviceSimChargeDto.MoonCountVo> moonCountVos = new JArrayList<>();
        //查询数据
        List<String> attrNames = Arrays.asList(
                LambdaUtils.getUnderlineCaseName(DeviceSimCharge::getMercId)
        );
        List<String> selectNames = Arrays.asList(
                attrNames.get(0),
                String.format("count(*) %s", LambdaUtils.getProperty(DeviceSimCharge::getSize)),
                String.format("sum(%s) %s", LambdaUtils.getUnderlineCaseName(DeviceSimCharge::getMoney), LambdaUtils.getProperty(DeviceSimCharge::getMoney))
        );
        QueryWrapper<DeviceSimCharge> queryWrapper = new QueryWrapper<DeviceSimCharge>()
                .select(selectNames.toArray(new String[selectNames.size()]))
                .in(Emptys.check(moonCountPage.getMercIds()), attrNames.get(0), moonCountPage.getMercIds())
                .between("DATE_FORMAT(" + LambdaUtils.getUnderlineCaseName(DeviceSimCharge::getCreateTime) + ", '%Y-%m-%d')", moonCountPage.getBeginDate(), moonCountPage.getEndDate())
                .groupBy(attrNames);
        IPage<DeviceSimCharge> iPage = page(toIPage(moonCountPage.getPage()), queryWrapper);
        List<DeviceSimCharge> records = iPage.getRecords();
        if (!Emptys.check(records)) {
            return R.ok(new PageBean<>());
        }
        String date = String.format("%s~%s", moonCountPage.getBeginDate(), moonCountPage.getEndDate());
        records.forEach(deviceSimCharge -> {
            DeviceSimChargeDto.MoonCountVo moonCountVo = new DeviceSimChargeDto.MoonCountVo()
                    .setDate(date)
                    .setMercId(deviceSimCharge.getMercId())
                    .setSimSize(deviceSimCharge.getSize())
                    .setMoney(deviceSimCharge.getMoney());
            moonCountVos.add(moonCountVo);
        });
        //翻译商户名称
        Beans.copy(moonCountVos).target(() -> mercService.list(new MercDto.SelectList().setMercIds(moonCountVos.getProperty(DeviceSimChargeDto.MoonCountVo::getMercId).comparing())).getData(),
                DeviceSimChargeDto.MoonCountVo::getMercId, DeviceSimChargeDto.MoonCountVo::getMercName, MercDto.Vo::getId, MercDto.Vo::getName)
                .builder();
        PageBean<DeviceSimChargeDto.MoonCountVo> pageBean = new PageBean<DeviceSimChargeDto.MoonCountVo>()
                .setCurrent(iPage.getCurrent())
                .setSize(iPage.getSize())
                .setTotal(iPage.getTotal())
                .setRecords(moonCountVos);
        return R.ok(pageBean);
    }

    @ApiOperation("月统计")
    @PostMapping("moonCount")
    public R<List<DeviceSimChargeDto.MoonCountVo>> moonCount(@RequestBody DeviceSimChargeDto.MoonCount moonCount) {
        JList<DeviceSimChargeDto.MoonCountVo> moonCountVos = new JArrayList<>();
        //查询数据
        List<String> attrNames = Arrays.asList(
                LambdaUtils.getUnderlineCaseName(DeviceSimCharge::getMercId),
                "DATE_FORMAT(" + LambdaUtils.getUnderlineCaseName(DeviceSimCharge::getCreateTime) + ", '%Y-%m')"
        );
        List<String> selectNames = Arrays.asList(
                attrNames.get(0),
                attrNames.get(1) + " " + LambdaUtils.getProperty(DeviceSimCharge::getNote),
                String.format("count(*) %s", LambdaUtils.getProperty(DeviceSimCharge::getSize)),
                String.format("sum(%s) %s", LambdaUtils.getUnderlineCaseName(DeviceSimCharge::getMoney), LambdaUtils.getProperty(DeviceSimCharge::getMoney))
        );
        List<String> dateDifference = deviceChargingHistoryService.getDateDifference(moonCount.getBeginDate(), moonCount.getEndDate());
        ThreadPoolUtils.Execute execute = ThreadPoolUtils.excPoll(DeviceThreadPoolConfig.DEVICE_COMMON_POLL, dateDifference.size());
        dateDifference.forEach(date -> execute.execute(() -> {
            QueryWrapper<DeviceSimCharge> queryWrapper = new QueryWrapper<DeviceSimCharge>()
                    .select(selectNames.get(0), selectNames.get(1), selectNames.get(2), selectNames.get(3))
                    .in(Emptys.check(moonCount.getMercIds()), attrNames.get(0), moonCount.getMercIds())
                    .eq(attrNames.get(1), date)
                    .groupBy(attrNames.get(0), attrNames.get(1));
            List<DeviceSimCharge> deviceSimCharges = list(queryWrapper);
            deviceSimCharges.forEach(deviceSimCharge -> {
                DeviceSimChargeDto.MoonCountVo moonCountVo = new DeviceSimChargeDto.MoonCountVo()
                        .setDate(deviceSimCharge.getNote())
                        .setMercId(deviceSimCharge.getMercId())
                        .setSimSize(deviceSimCharge.getSize())
                        .setMoney(deviceSimCharge.getMoney());
                moonCountVos.add(moonCountVo);
            });
        }));
        execute.end();
        //翻译商户名称
        Beans.copy(moonCountVos).target(() -> mercService.list(new MercDto.SelectList().setMercIds(moonCountVos.getProperty(DeviceSimChargeDto.MoonCountVo::getMercId).comparing())).getData(),
                DeviceSimChargeDto.MoonCountVo::getMercId, DeviceSimChargeDto.MoonCountVo::getMercName, MercDto.Vo::getId, MercDto.Vo::getName)
                .builder();
        return R.ok(moonCountVos.desc(DeviceSimChargeDto.MoonCountVo::getDate));
    }

    @SneakyThrows
    @ApiOperation("月统计导出")
    @PostMapping("moonCountDownload")
    public void moonCountDownload(@RequestBody DeviceSimChargeDto.MoonCount moonCount) {
        //生成excel
        String name = YitIdHelper.nextId() + ".xlsx";
        String path = fileConfig.getPath() + File.separator + name;
        ExcelUtils.SheetAndData<MoonCountData> sheetAndData = ExcelUtils.create(path, MoonCountData.class);
        sheetAndData.sheet("设备流量卡月统计数据", () -> {
            List<DeviceSimChargeDto.MoonCountVo> data = moonCount(moonCount).getData();
            if (!Emptys.check(data)) {
                return null;
            }
            return Beans.copy(MoonCountData.class, data);
        }).builder();
        //下载文件
        InputStream inputStream = IoUtils.inputStream(path).get();
        response.setHeader("Content-Disposition", "attachment; filename=" + "设备管理费月统计数据.xlsx");
        response.setContentType("application/xlsx");
        byte[] buffer = new byte[1024];
        int bytesRead;
        OutputStream outputStream = response.getOutputStream();
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        inputStream.close();
        outputStream.close();
        //删除文件
        new File(path).delete();
    }

    @Data
    @Accessors(chain = true)
    public static class MoonCountData {

        @ColumnWidth(25)
        @ExcelProperty(value = "统计时间 yyyy-MM")
        private String date;

        @ColumnWidth(25)
        @ExcelProperty(value = "商户id")
        private Long mercId;

        @ColumnWidth(25)
        @ExcelProperty(value = "商户名称")
        private String mercName;

        @ColumnWidth(25)
        @ExcelProperty(value = "卡数")
        private Integer simSize;

        @ColumnWidth(25)
        @ExcelProperty(value = "续费金额")
        private Integer money;
    }
}