package com.kym.service.miniapp;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.kym.common.config.HuapiaoerProperties;
import com.kym.entity.admin.InvoiceDetail;
import com.kym.entity.miniapp.Invoice;
import com.kym.entity.wechat.FaPiao;
import com.kym.entity.wechat.FapiaoApplications;
import com.kym.entity.wechat.InvoiceOrderDetail;
import com.kym.huapiaoer.HuapiaoerClient;
import com.kym.huapiaoer.HuapiaoerConfig;
import com.kym.huapiaoer.HuapiaoerException;
import com.kym.huapiaoer.enums.InvoiceQueryType;
import com.kym.huapiaoer.enums.InvoiceType;
import com.kym.huapiaoer.enums.PayType;
import com.kym.huapiaoer.model.request.OpenBlueInvoiceRequest;
import com.kym.huapiaoer.model.response.InvoiceInfo;
import com.kym.huapiaoer.model.response.OpenInvoiceResponse;
import com.kym.service.admin.InvoiceDetailService;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
@RequiredArgsConstructor
public class HuapiaoerInvoiceService {

    private final HuapiaoerProperties properties;
    private final InvoiceDetailService invoiceDetailService;

    private HuapiaoerClient client;
    private volatile String issuerId;
    private volatile boolean issuerIdTried;

    @PostConstruct
    public void init() {
        this.client = new HuapiaoerClient(
                HuapiaoerConfig.builder()
                        .baseUrl(properties.getBaseUrl())
                        .appSecret(properties.getAppSecret())
                        .build()
        );
    }

    private String getIssuerId() {
        if (!issuerIdTried) {
            synchronized (this) {
                if (!issuerIdTried) {
                    issuerIdTried = true;
                    try {
                        var drawers = client.getDrawerIdList(properties.getNsrsbh());
                        if (!drawers.isEmpty()) {
                            issuerId = drawers.get(0).getIssuerid();
                            log.info("航信开票人获取成功, nsrsbh:{}, issuerId:{}", properties.getNsrsbh(), issuerId);
                        }
                    } catch (Exception e) {
                        log.warn("获取航信开票人列表失败, nsrsbh:{}, msg:{}", properties.getNsrsbh(), e.getMessage());
                    }
                }
            }
        }
        return issuerId;
    }

    /**
     * 开具蓝字发票
     */
    @DS("db-miniapp")
    public OpenInvoiceResponse openBlueInvoice(Invoice invoice) {
        var request = buildOpenBlueInvoiceRequest(invoice);
        try {
            var resp = client.openBlueInvoice(request);
            log.info("航信开票请求成功, applyId:{}, resp:{}", invoice.getApplyId(), JSONObject.toJSONString(resp));
            return resp;
        } catch (HuapiaoerException e) {
            log.error("航信开票失败, applyId:{}, code:{}, msg:{}", invoice.getApplyId(), e.getCode(), e.getMessage());
            throw e;
        }
    }

    /**
     * 查询开票结果
     */
    public InvoiceInfo queryInvoiceResult(String orderId, int invoiceType) {
        return client.getInvoice(orderId, invoiceType);
    }

    /**
     * 发送发票邮件
     */
    public void sendInvoiceEmail(String orderId, int invoiceType, String email) {
        try {
            var resp = client.sendMail(orderId, invoiceType, email);
            log.info("航信发票邮件发送, orderId:{}, email:{}, resp:{}", orderId, email, JSONObject.toJSONString(resp));
        } catch (HuapiaoerException e) {
            log.error("航信发票邮件发送失败, orderId:{}, code:{}, msg:{}", orderId, e.getCode(), e.getMessage());
        }
    }

    /**
     * 根据航信查询结果更新开票详情
     */
    public void updateInvoiceDetailFromResult(Invoice invoice, InvoiceInfo result) {
        try {
            DynamicDataSourceContextHolder.push("db-admin");

            var ticketDate = result.getTicketDate();
            if (ticketDate != null && ticketDate.length() == 16) { // "yyyy-MM-dd HH:mm" = 16 chars, pad to 19
                ticketDate += ":00";
            }
            var fapiaoTime = ticketDate != null
                    ? DateUtil.parse(ticketDate, "yyyy-MM-dd HH:mm:ss").toLocalDateTime()
                    : LocalDateTime.now();
            var totalAmount = (int) (Double.parseDouble(result.getTicketTotalAmountHasTax()) * 100);

            var blueFapiao = new FapiaoApplications.FapiaoInfo();
            blueFapiao.setFapiao_code(result.getInvoicecode());
            blueFapiao.setFapiao_number(result.getInvoicenumber());
            blueFapiao.setFapiao_time(result.getTicketDate());

            var buyerInformation = new FaPiao.BuyerInformation()
                    .setType(invoice.getInvoiceType())
                    .setName(invoice.getInvoiceTitle())
                    .setTaxpayer_id(invoice.getTaxId())
                    .setAddress(invoice.getAddress())
                    .setTelephone(invoice.getTelephone())
                    .setBank_name(invoice.getBankName())
                    .setBank_account(invoice.getBankAccount())
                    .setPhone(invoice.getPhone())
                    .setEmail(invoice.getEmail());

            var invoiceDetail = new InvoiceDetail()
                    .setApplyId(invoice.getApplyId())
                    .setStatus("ISSUED")
                    .setFapiaoTime(fapiaoTime)
                    .setBlueFapiao(blueFapiao)
                    .setTotalAmount(totalAmount)
                    .setBuyerInformation(buyerInformation)
                    .setInvoiceUrl(result.getInvoiceurl())
                    .setOfdUrl(result.getOfdurl())
                    .setXmlUrl(result.getXmlurl());

            invoiceDetailService.createManualInvoiceDetail(invoiceDetail);
        } finally {
            DynamicDataSourceContextHolder.poll();
        }
    }

    /**
     * 获取发票下载地址
     */
    public Map<String, String> getInvoiceDownloadUrls(Long invoiceId, InvoiceDetail invoiceDetail) {
        if (invoiceDetail == null) {
            return Map.of();
        }
        return Map.of(
                "invoiceUrl", invoiceDetail.getInvoiceUrl() != null ? invoiceDetail.getInvoiceUrl() : "",
                "ofdUrl", invoiceDetail.getOfdUrl() != null ? invoiceDetail.getOfdUrl() : "",
                "xmlUrl", invoiceDetail.getXmlUrl() != null ? invoiceDetail.getXmlUrl() : ""
        );
    }

    private OpenBlueInvoiceRequest buildOpenBlueInvoiceRequest(Invoice invoice) {
        var orderDetails = invoice.getOrderDetails();

        int elecMoney = orderDetails.stream().mapToInt(InvoiceOrderDetail::getElecMoney).sum();
        int serviceMoney = orderDetails.stream().mapToInt(InvoiceOrderDetail::getServiceMoney).sum();
        int discount = orderDetails.stream().mapToInt(InvoiceOrderDetail::getServiceMoneyDiscount).sum();
        int netServiceMoney = serviceMoney - discount;

        var details = new ArrayList<OpenBlueInvoiceRequest.DetailInfo>();

        if (elecMoney > 0) {
            details.add(new OpenBlueInvoiceRequest.DetailInfo()
                    .setGoodsname("充电电费")
                    .setPrice(elecMoney / 100.0)
                    .setSl(1.0)
                    .setTaxcode("1100101020200000000")
                    .setTax("0.13"));
        }

        if (netServiceMoney > 0) {
            details.add(new OpenBlueInvoiceRequest.DetailInfo()
                    .setGoodsname("充电服务费")
                    .setPrice(netServiceMoney / 100.0)
                    .setSl(1.0)
                    .setTaxcode("1100101020200000000")
                    .setTax("0.13"));
        }

        var invoiceTypeCode = InvoiceType.DIGITAL_NORMAL.getCode();

        var head = new OpenBlueInvoiceRequest.HeadInfo()
                .setOrderId(invoice.getApplyId())
                .setB2cshopid(properties.getB2cshopid())
                .setKpje(String.valueOf(invoice.getInvoiceAmount() / 100.0))
                .setInvoicetitle(invoice.getInvoiceTitle())
                .setRegistrationnumber(invoice.getTaxId())
                .setCompanyaddress(invoice.getAddress())
                .setMobilenumber(invoice.getPhone())
                .setOpenaccountbank(invoice.getBankName())
                .setBankaccount(invoice.getBankAccount())
                .setRemark(invoice.getRemark())
                .setRecmail(invoice.getEmail())
                .setInvoiceTypeCode(invoiceTypeCode);

        return new OpenBlueInvoiceRequest()
                .setIssuerid(getIssuerId())
                .setHead(head)
                .setDetails(details)
                .setTradeinfo(new OpenBlueInvoiceRequest.TradeInfo()
                        .setPayType(PayType.WECHAT_PAY.getCode())
                        .setOutTradeNo(invoice.getApplyId()));
    }
}
