package com.huimv.employment.service.settlement;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.huimv.employment.common.exception.BizException;
import com.huimv.employment.common.exception.ErrorCode;
import com.huimv.employment.dao.entity.FeEmploymentOrder;
import com.huimv.employment.dao.entity.FeEnterprise;
import com.huimv.employment.dao.entity.FeOrderInvoice;
import com.huimv.employment.dao.entity.FeSettlementOrder;
import com.huimv.employment.dao.mapper.FeEmploymentOrderMapper;
import com.huimv.employment.dao.mapper.FeOrderInvoiceMapper;
import com.huimv.employment.dao.mapper.FeSettlementOrderMapper;
import com.huimv.employment.service.enterprise.EnterpriseService;
import com.huimv.employment.service.order.dto.OrderCompleteRequest;
import com.huimv.employment.service.settlement.dto.OrderInvoiceResponse;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 订单开票归档信息：查询预填、办结时落库。
 */
@Service
public class OrderInvoiceService {

    private static final String STATUS_CANCELLED = "cancelled";
    private static final String INVOICE_TYPE_SPECIAL = "vat_special";
    private static final String INVOICE_TYPE_NORMAL = "vat_normal";
    private static final String STATUS_DRAFT = "draft";
    private static final String STATUS_ARCHIVED = "archived";
    private static final BigDecimal DEFAULT_TAX_RATE = new BigDecimal("0.0600");

    private final FeOrderInvoiceMapper feOrderInvoiceMapper;
    private final FeEmploymentOrderMapper feEmploymentOrderMapper;
    private final FeSettlementOrderMapper feSettlementOrderMapper;
    private final EnterpriseService enterpriseService;

    public OrderInvoiceService(FeOrderInvoiceMapper feOrderInvoiceMapper,
                               FeEmploymentOrderMapper feEmploymentOrderMapper,
                               FeSettlementOrderMapper feSettlementOrderMapper,
                               EnterpriseService enterpriseService) {
        this.feOrderInvoiceMapper = feOrderInvoiceMapper;
        this.feEmploymentOrderMapper = feEmploymentOrderMapper;
        this.feSettlementOrderMapper = feSettlementOrderMapper;
        this.enterpriseService = enterpriseService;
    }

    /**
     * 查询开票信息：已保存则返回库数据；否则按结算单+企业预填。
     */
    public OrderInvoiceResponse getInvoice(Long userId, Long orderId) {
        FeEmploymentOrder order = requireOwnedOrder(userId, orderId);
        FeSettlementOrder settlement = findActiveSettlement(orderId);
        FeEnterprise enterprise = order.getEnterpriseId() != null
                ? enterpriseService.requireById(order.getEnterpriseId()) : null;
        FeOrderInvoice saved = findByOrderId(orderId);

        OrderInvoiceResponse response;
        if (saved != null) {
            response = toResponse(order, settlement, saved);
            response.setMessage("开票信息");
        } else {
            response = buildPreview(order, settlement, enterprise);
            response.setMessage("开票信息预填（尚未归档保存）");
        }
        return response;
    }

    /**
     * 开票归档时 upsert 开票信息并标记 archived。
     */
    @Transactional(rollbackFor = Exception.class)
    public FeOrderInvoice saveOnArchive(Long userId,
                                        FeEmploymentOrder order,
                                        FeSettlementOrder settlement,
                                        OrderCompleteRequest request,
                                        LocalDateTime now) {
        FeEnterprise enterprise = order.getEnterpriseId() != null
                ? enterpriseService.requireById(order.getEnterpriseId()) : null;
        OrderCompleteRequest req = request != null ? request : new OrderCompleteRequest();

        BigDecimal billable = resolveBillable(settlement);
        BigDecimal invoiceAmount = req.getInvoiceAmount() != null
                ? req.getInvoiceAmount().setScale(2, RoundingMode.HALF_UP) : billable;
        BigDecimal taxRate = req.getTaxRate() != null
                ? req.getTaxRate().setScale(4, RoundingMode.HALF_UP) : DEFAULT_TAX_RATE;
        if (taxRate.compareTo(BigDecimal.ZERO) < 0) {
            throw new BizException(ErrorCode.BAD_REQUEST, "税率不能为负");
        }
        BigDecimal taxAmount = req.getTaxAmount() != null
                ? req.getTaxAmount().setScale(2, RoundingMode.HALF_UP)
                : invoiceAmount.multiply(taxRate).setScale(2, RoundingMode.HALF_UP);
        BigDecimal totalWithTax = req.getTotalWithTax() != null
                ? req.getTotalWithTax().setScale(2, RoundingMode.HALF_UP)
                : invoiceAmount.add(taxAmount).setScale(2, RoundingMode.HALF_UP);

        String invoiceType = resolveInvoiceType(req.getInvoiceType());
        String companyName = StringUtils.hasText(req.getCompanyName())
                ? req.getCompanyName().trim()
                : (enterprise != null ? enterprise.getName() : null);
        String creditCode = StringUtils.hasText(req.getCreditCode())
                ? req.getCreditCode().trim()
                : (enterprise != null ? enterprise.getCreditCode() : null);
        if (!StringUtils.hasText(companyName)) {
            throw new BizException(ErrorCode.BAD_REQUEST, "开票企业名称不能为空");
        }
        if (!StringUtils.hasText(creditCode)) {
            throw new BizException(ErrorCode.BAD_REQUEST, "统一社会信用代码不能为空");
        }

        FeOrderInvoice existing = findByOrderId(order.getId());
        FeOrderInvoice entity = existing != null ? existing : new FeOrderInvoice();
        entity.setOrderId(order.getId());
        entity.setSettlementId(settlement != null ? settlement.getId() : null);
        entity.setEnterpriseId(order.getEnterpriseId());
        entity.setInvoiceType(invoiceType);
        entity.setTaxRate(taxRate);
        entity.setBillableAmount(billable);
        entity.setInvoicedAmount(invoiceAmount);
        entity.setPendingAmount(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP));
        entity.setInvoiceAmount(invoiceAmount);
        entity.setTaxAmount(taxAmount);
        entity.setTotalWithTax(totalWithTax);
        entity.setCompanyName(companyName);
        entity.setCreditCode(creditCode);
        entity.setBankAccountInfo(StringUtils.hasText(req.getBankAccountInfo())
                ? req.getBankAccountInfo().trim() : entity.getBankAccountInfo());
        entity.setInvoiceNo(StringUtils.hasText(req.getInvoiceNo()) ? req.getInvoiceNo().trim() : null);
        entity.setTaxVoucherNo(StringUtils.hasText(req.getTaxVoucherNo()) ? req.getTaxVoucherNo().trim() : null);
        entity.setRemark(StringUtils.hasText(req.getRemark()) ? req.getRemark().trim() : null);
        entity.setInvoiceStatus(STATUS_ARCHIVED);
        entity.setArchivedAt(now);
        entity.setArchivedBy(userId);
        entity.setUpdateTime(now);
        // MVP Mock 凭证链接（已有则保留）
        if (!StringUtils.hasText(entity.getInvoiceFileUrl())) {
            entity.setInvoiceFileUrl("/mock/invoice/" + order.getOrderNo() + ".pdf");
        }
        if (!StringUtils.hasText(entity.getTaxFileUrl())) {
            entity.setTaxFileUrl("/mock/tax/" + order.getOrderNo() + ".pdf");
        }
        if (!StringUtils.hasText(entity.getComplianceFileUrl())) {
            entity.setComplianceFileUrl("/mock/compliance/" + order.getOrderNo() + ".pdf");
        }

        if (existing == null) {
            entity.setCreateTime(now);
            entity.setDelFlag(0);
            feOrderInvoiceMapper.insert(entity);
        } else {
            feOrderInvoiceMapper.updateById(entity);
        }
        return entity;
    }

    private OrderInvoiceResponse buildPreview(FeEmploymentOrder order,
                                              FeSettlementOrder settlement,
                                              FeEnterprise enterprise) {
        BigDecimal billable = resolveBillable(settlement);
        BigDecimal taxRate = DEFAULT_TAX_RATE;
        BigDecimal taxAmount = billable.multiply(taxRate).setScale(2, RoundingMode.HALF_UP);
        BigDecimal total = billable.add(taxAmount).setScale(2, RoundingMode.HALF_UP);

        OrderInvoiceResponse response = new OrderInvoiceResponse();
        response.setOrderId(order.getId());
        response.setOrderNo(order.getOrderNo());
        response.setSettlementId(settlement != null ? settlement.getId() : null);
        response.setCurrentStepCode(order.getCurrentStepCode());
        response.setInvoiceStatus(STATUS_DRAFT);
        response.setInvoiceType(INVOICE_TYPE_SPECIAL);
        response.setInvoiceTypeText(invoiceTypeText(INVOICE_TYPE_SPECIAL));
        response.setTaxRate(taxRate);
        response.setBillableAmount(billable);
        response.setInvoicedAmount(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP));
        response.setPendingAmount(billable);
        response.setInvoiceAmount(billable);
        response.setTaxAmount(taxAmount);
        response.setTotalWithTax(total);
        if (enterprise != null) {
            response.setCompanyName(enterprise.getName());
            response.setCreditCode(enterprise.getCreditCode());
        }
        response.setFiles(emptyFiles());
        response.setComplianceTip("本单据符合五流合一，可全额税前扣除");
        return response;
    }

    private OrderInvoiceResponse toResponse(FeEmploymentOrder order,
                                            FeSettlementOrder settlement,
                                            FeOrderInvoice invoice) {
        OrderInvoiceResponse response = new OrderInvoiceResponse();
        response.setOrderId(order.getId());
        response.setOrderNo(order.getOrderNo());
        response.setSettlementId(invoice.getSettlementId() != null
                ? invoice.getSettlementId()
                : (settlement != null ? settlement.getId() : null));
        response.setCurrentStepCode(order.getCurrentStepCode());
        response.setInvoiceStatus(invoice.getInvoiceStatus());
        response.setInvoiceType(invoice.getInvoiceType());
        response.setInvoiceTypeText(invoiceTypeText(invoice.getInvoiceType()));
        response.setTaxRate(invoice.getTaxRate());
        response.setBillableAmount(invoice.getBillableAmount());
        response.setInvoicedAmount(invoice.getInvoicedAmount());
        response.setPendingAmount(invoice.getPendingAmount());
        response.setInvoiceAmount(invoice.getInvoiceAmount());
        response.setTaxAmount(invoice.getTaxAmount());
        response.setTotalWithTax(invoice.getTotalWithTax());
        response.setCompanyName(invoice.getCompanyName());
        response.setCreditCode(invoice.getCreditCode());
        response.setBankAccountInfo(invoice.getBankAccountInfo());
        response.setInvoiceNo(invoice.getInvoiceNo());
        response.setTaxVoucherNo(invoice.getTaxVoucherNo());
        response.setArchivedAt(invoice.getArchivedAt());
        response.setFiles(toFiles(invoice));
        response.setComplianceTip("本单据符合五流合一，可全额税前扣除");
        return response;
    }

    private static List<OrderInvoiceResponse.DownloadFile> toFiles(FeOrderInvoice invoice) {
        List<OrderInvoiceResponse.DownloadFile> files = new ArrayList<>();
        files.add(new OrderInvoiceResponse.DownloadFile(
                "vat_invoice", "增值税专用发票", invoice.getInvoiceFileUrl()));
        files.add(new OrderInvoiceResponse.DownloadFile(
                "tax_certificate", "完税证明", invoice.getTaxFileUrl()));
        files.add(new OrderInvoiceResponse.DownloadFile(
                "compliance_chain", "合规证据链", invoice.getComplianceFileUrl()));
        return files;
    }

    private static List<OrderInvoiceResponse.DownloadFile> emptyFiles() {
        List<OrderInvoiceResponse.DownloadFile> files = new ArrayList<>();
        files.add(new OrderInvoiceResponse.DownloadFile("vat_invoice", "增值税专用发票", null));
        files.add(new OrderInvoiceResponse.DownloadFile("tax_certificate", "完税证明", null));
        files.add(new OrderInvoiceResponse.DownloadFile("compliance_chain", "合规证据链", null));
        return files;
    }

    private static BigDecimal resolveBillable(FeSettlementOrder settlement) {
        if (settlement == null) {
            return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        }
        BigDecimal amount = settlement.getInvoiceAmount() != null
                ? settlement.getInvoiceAmount()
                : settlement.getTotalOutflow();
        if (amount == null) {
            return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        }
        return amount.setScale(2, RoundingMode.HALF_UP);
    }

    private static String resolveInvoiceType(String raw) {
        if (!StringUtils.hasText(raw)) {
            return INVOICE_TYPE_SPECIAL;
        }
        String v = raw.trim().toLowerCase();
        if (INVOICE_TYPE_SPECIAL.equals(v) || "special".equals(v) || "专用发票".equals(raw.trim())) {
            return INVOICE_TYPE_SPECIAL;
        }
        if (INVOICE_TYPE_NORMAL.equals(v) || "normal".equals(v) || "普通发票".equals(raw.trim())) {
            return INVOICE_TYPE_NORMAL;
        }
        return INVOICE_TYPE_SPECIAL;
    }

    private static String invoiceTypeText(String type) {
        if (INVOICE_TYPE_NORMAL.equals(type)) {
            return "增值税普通发票";
        }
        return "增值税专用发票";
    }

    private FeOrderInvoice findByOrderId(Long orderId) {
        return feOrderInvoiceMapper.selectOne(new LambdaQueryWrapper<FeOrderInvoice>()
                .eq(FeOrderInvoice::getOrderId, orderId)
                .orderByDesc(FeOrderInvoice::getId)
                .last("LIMIT 1"));
    }

    private FeSettlementOrder findActiveSettlement(Long orderId) {
        return feSettlementOrderMapper.selectOne(new LambdaQueryWrapper<FeSettlementOrder>()
                .eq(FeSettlementOrder::getOrderId, orderId)
                .ne(FeSettlementOrder::getSettlementStatus, STATUS_CANCELLED)
                .orderByDesc(FeSettlementOrder::getId)
                .last("LIMIT 1"));
    }

    private FeEmploymentOrder requireOwnedOrder(Long userId, Long orderId) {
        enterpriseService.requireEnterpriseUser(userId);
        FeEnterprise enterprise = enterpriseService.findEnterpriseByUserId(userId);
        if (enterprise == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "请先完成企业登记");
        }
        if (orderId == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "订单 ID 无效");
        }
        FeEmploymentOrder order = feEmploymentOrderMapper.selectById(orderId);
        if (order == null) {
            throw new BizException(ErrorCode.NOT_FOUND, "用工订单不存在");
        }
        if (order.getEnterpriseId() == null || !order.getEnterpriseId().equals(enterprise.getId())) {
            if (order.getUserId() == null || !order.getUserId().equals(userId)) {
                throw new BizException(ErrorCode.FORBIDDEN, "无权操作该订单");
            }
        }
        return order;
    }
}
