package com.kym.service.admin.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.github.pagehelper.PageHelper;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.kym.common.utils.CommUtil;
import com.kym.entity.admin.InvoiceDetail;
import com.kym.entity.admin.queryParams.InvoiceDetailQueryParam;
import com.kym.entity.common.PageBean;
import com.kym.entity.miniapp.Invoice;
import com.kym.mapper.admin.InvoiceDetailMapper;
import com.kym.service.admin.InvoiceDetailService;
import com.kym.service.miniapp.DataDictService;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>
 * 发票详情表 服务实现类
 * </p>
 *
 * @author skyline
 * @since 2024-03-19
 */
@Service
public class InvoiceDetailServiceImpl extends MPJBaseServiceImpl<InvoiceDetailMapper, InvoiceDetail> implements InvoiceDetailService {

    private final DataDictService dataDictService;

    public InvoiceDetailServiceImpl(DataDictService dataDictService) {
        this.dataDictService = dataDictService;
    }


    @Override
    public PageBean<InvoiceDetail> listInvoiceDetail(InvoiceDetailQueryParam params) {
        PageHelper.startPage(params.getPageNum(), params.getPageSize());
        var res = buildQuery(params).orderByDesc(InvoiceDetail::getFapiaoTime).list();
        return new PageBean<>(res);
    }

    @Override
    public ExcelWriter exportInvoiceDetail(InvoiceDetailQueryParam params) {
        var invoiceDetailList = buildQuery(params).orderByDesc(InvoiceDetail::getFapiaoTime).list();
        ExcelWriter writer = ExcelUtil.getWriter();

        // excel 行信息
        List<Map<String, Object>> rows = new ArrayList<>();

        invoiceDetailList.forEach(invoiceDetail -> {
            // 发票公共信息
            var blueFapiao = invoiceDetail.getBlueFapiao();
            var buyerInfo = invoiceDetail.getBuyerInformation();

            Map<String, Object> baseInfo = new HashMap<>();
            baseInfo.put("blue_fapiao.fapiao_time", invoiceDetail.getFapiaoTime());
            baseInfo.put("blue_fapiao.fapiao_number", blueFapiao != null ? blueFapiao.getFapiao_number() : "");
            baseInfo.put("buyer_information.type", buyerInfo != null && Invoice.TYPE_企业.equals(buyerInfo.getType()) ? "企业" : "个人");
            baseInfo.put("buyer_information.name", buyerInfo != null ? buyerInfo.getName() : "");
            baseInfo.put("buyer_information.taxpayer_id", buyerInfo != null ? buyerInfo.getTaxpayer_id() : "");
            baseInfo.put("fapiao_information.status", "REVERSED".equals(invoiceDetail.getStatus()) ? "是" : "否");

            var items = invoiceDetail.getItems();
            if (items != null && !items.isEmpty()) {
                // 旧版微信发票：含发票行明细，每行展开一条记录
                items.forEach(item -> {
                    var row = new HashMap<>(baseInfo);
                    row.put("goods_name", item.getGoods_name());
                    row.put("quantity", item.getQuantity() / 100000000);
                    row.put("amount", NumberUtil.decimalFormat("#.##", item.getAmount() / 100f));
                    row.put("tax_amount", NumberUtil.decimalFormat("#.##", item.getTax_amount() / 100f));
                    row.put("tax_rate", NumberUtil.decimalFormat("#.##", item.getTax_rate() / 10000f));
                    rows.add(row);
                });
            } else {
                // 新版航信发票：无发票行明细，根据含税总金额反算各项（税率固定13%）
                var row = new HashMap<>(baseInfo);
                var totalAmount = invoiceDetail.getTotalAmount();
                if (totalAmount != null && totalAmount > 0) {
                    double totalYuan = totalAmount / 100.0;
                    double amountYuan = totalYuan / 1.13;
                    double taxYuan = totalYuan - amountYuan;
                    row.put("goods_name", "充电费用");
                    row.put("quantity", 1);
                    row.put("amount", NumberUtil.decimalFormat("#.##", amountYuan));
                    row.put("tax_amount", NumberUtil.decimalFormat("#.##", taxYuan));
                    row.put("tax_rate", "13%");
                    row.put("total_amount_has_tax", NumberUtil.decimalFormat("#.##", totalYuan));
                } else {
                    row.put("goods_name", "");
                    row.put("quantity", "");
                    row.put("amount", "");
                    row.put("tax_amount", "");
                    row.put("tax_rate", "");
                    row.put("total_amount_has_tax", "");
                }
                rows.add(row);
            }
        });

        writer.addHeaderAlias("blue_fapiao.fapiao_number", "发票号码");
        writer.addHeaderAlias("blue_fapiao.fapiao_time", "开票日期");
        writer.addHeaderAlias("goods_name", "货物、应税劳务及服务");
        writer.addHeaderAlias("quantity", "数量");
        writer.addHeaderAlias("amount", "金额");
        writer.addHeaderAlias("tax_rate", "税率");
        writer.addHeaderAlias("tax_amount", "税额");
        writer.addHeaderAlias("total_amount_has_tax", "价税合计");
        writer.addHeaderAlias("fapiao_information.status", "是否作废");
        writer.addHeaderAlias("buyer_information.type", "购买方类型");
        writer.addHeaderAlias("buyer_information.name", "购方单位名称");
        writer.addHeaderAlias("buyer_information.taxpayer_id", "购方识别号");

        writer.write(rows, true);

        return writer;

    }

    @Override
    @DS("db-admin")
    public void createManualInvoiceDetail(InvoiceDetail invoiceDetail) {
        removeByMap(Map.of("apply_id", invoiceDetail.getApplyId()));
        save(invoiceDetail);
    }

    /**
     * 构建带公共过滤条件的查询
     */
    private LambdaQueryChainWrapper<InvoiceDetail> buildQuery(InvoiceDetailQueryParam params) {
        return lambdaQuery()
                .eq(CommUtil.isNotEmptyAndNull(params.getApplyId()), InvoiceDetail::getApplyId, params.getApplyId())
                .ge(params.getStartTime() != null, InvoiceDetail::getFapiaoTime, params.getStartTime())
                .le(params.getEndTime() != null, InvoiceDetail::getFapiaoTime, params.getEndTime());
    }
}
