package com.erp.finance.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.erp.finance.dto.AccountsPayableQueryRequest;
import com.erp.finance.entity.AccountsPayable;
import com.erp.finance.entity.PaymentRecord;
import com.erp.finance.repository.AccountsPayableRepository;
import com.erp.finance.repository.PaymentRecordRepository;
import com.erp.finance.service.AccountsPayableService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.atomic.AtomicLong;

@Slf4j
@Service
@RequiredArgsConstructor
public class AccountsPayableServiceImpl implements AccountsPayableService {

    private final AccountsPayableRepository apRepository;
    private final PaymentRecordRepository paymentRepository;
    private static final AtomicLong AP_COUNTER = new AtomicLong(System.currentTimeMillis() % 100000);

    @Override
    @Transactional
    public AccountsPayable create(AccountsPayableCreateRequest request) {
        log.info("[财务] 创建应付账款 purchaseOrderNo={}, supplierId={}, amount={}",
                request.getPurchaseOrderNo(), request.getSupplierId(), request.getAmount());

        // 检查是否已存在
        AccountsPayable existing = apRepository.findByPurchaseOrderNo(request.getPurchaseOrderNo());
        if (existing != null) {
            log.warn("[财务] 应付账款已存在 purchaseOrderNo={}, apNo={}",
                    request.getPurchaseOrderNo(), existing.getApNo());
            return existing;
        }

        String apNo = generateApNo();
        AccountsPayable ap = AccountsPayable.builder()
                .apNo(apNo)
                .purchaseOrderNo(request.getPurchaseOrderNo())
                .purchaseOrderId(request.getPurchaseOrderId())
                .supplierId(request.getSupplierId())
                .supplierName(request.getSupplierName())
                .totalAmount(request.getAmount())
                .inboundAmount(BigDecimal.ZERO)
                .paidAmount(BigDecimal.ZERO)
                .unpaidAmount(request.getAmount())
                .currency("CNY")
                .paymentMethod(request.getPaymentMethod())
                .dueDate(request.getDueDate())
                .status(AccountsPayable.STATUS_PENDING)
                .inboundStatus(AccountsPayable.INBOUND_PENDING)
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .deleted(0)
                .build();

        apRepository.insert(ap);
        log.info("[财务] 应付账款创建成功 apNo={}, purchaseOrderNo={}, amount={}",
                apNo, request.getPurchaseOrderNo(), request.getAmount());
        return ap;
    }

    @Override
    @Transactional
    public void cancel(String purchaseOrderNo) {
        AccountsPayable ap = apRepository.findByPurchaseOrderNo(purchaseOrderNo);
        if (ap == null) {
            log.warn("[财务] 应付账款不存在 purchaseOrderNo={}", purchaseOrderNo);
            return;
        }
        if (AccountsPayable.STATUS_PAID.equals(ap.getStatus())) {
            throw new RuntimeException("已付款的应付账款不能取消");
        }
        ap.setStatus(AccountsPayable.STATUS_CANCELLED);
        ap.setUpdateTime(LocalDateTime.now());
        apRepository.updateById(ap);
        log.info("[财务] 应付账款取消 apNo={}, purchaseOrderNo={}", ap.getApNo(), purchaseOrderNo);
    }

    @Override
    @Transactional
    public void updateInboundStatus(String purchaseOrderNo, String inboundNo, BigDecimal inboundAmount, String action) {
        AccountsPayable ap = apRepository.findByPurchaseOrderNo(purchaseOrderNo);
        if (ap == null) {
            log.warn("[财务] 应付账款不存在 purchaseOrderNo={}", purchaseOrderNo);
            return;
        }

        log.info("[财务] 更新入库状态 apNo={}, inboundNo={}, inboundAmount={}, action={}",
                ap.getApNo(), inboundNo, inboundAmount, action);

        // 更新已入库金额
        ap.setInboundAmount(inboundAmount);

        // 判断入库完成度
        if (ap.getTotalAmount().compareTo(BigDecimal.ZERO) > 0) {
            int compare = inboundAmount.compareTo(ap.getTotalAmount());
            if (compare >= 0) {
                ap.setInboundStatus(AccountsPayable.INBOUND_COMPLETED);
            } else if (inboundAmount.compareTo(BigDecimal.ZERO) > 0) {
                ap.setInboundStatus(AccountsPayable.INBOUND_PARTIAL);
            }
        }

        ap.setUpdateTime(LocalDateTime.now());
        apRepository.updateById(ap);

        // 如果是取消入库
        if ("cancel".equals(action)) {
            ap.setInboundAmount(BigDecimal.ZERO);
            ap.setInboundStatus(AccountsPayable.INBOUND_PENDING);
            apRepository.updateById(ap);
        }

        log.info("[财务] 入库状态更新完成 apNo={}, inboundStatus={}, inboundAmount={}",
                ap.getApNo(), ap.getInboundStatus(), ap.getInboundAmount());
    }

    @Override
    @Transactional
    public PaymentRecord confirmPayment(PaymentConfirmRequest request) {
        AccountsPayable ap = apRepository.findByApNo(request.getApNo());
        if (ap == null) {
            throw new RuntimeException("应付账款不存在: " + request.getApNo());
        }
        if (AccountsPayable.STATUS_CANCELLED.equals(ap.getStatus())) {
            throw new RuntimeException("应付账款已取消");
        }
        if (ap.getUnpaidAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new RuntimeException("应付账款已付清，无需再付款");
        }

        // 创建付款记录
        String paymentNo = generatePaymentNo();
        PaymentRecord payment = PaymentRecord.builder()
                .paymentNo(paymentNo)
                .apNo(ap.getApNo())
                .apId(ap.getId())
                .purchaseOrderNo(ap.getPurchaseOrderNo())
                .supplierId(ap.getSupplierId())
                .supplierName(ap.getSupplierName())
                .amount(request.getAmount())
                .paymentMethod(request.getPaymentMethod())
                .fromAccount(request.getFromAccount())
                .toAccount(request.getToAccount())
                .paymentTime(LocalDateTime.now())
                .bankFlowNo(request.getBankFlowNo())
                .status(PaymentRecord.STATUS_COMPLETED)
                .purpose(PaymentRecord.PURPOSE_PURCHASE)
                .relatedId(ap.getPurchaseOrderId())
                .relatedType("purchase_order")
                .operator(request.getOperator())
                .remark(request.getRemark())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .deleted(0)
                .build();

        paymentRepository.insert(payment);

        // 更新应付账款
        BigDecimal newPaidAmount = ap.getPaidAmount().add(request.getAmount());
        BigDecimal newUnpaidAmount = ap.getTotalAmount().subtract(newPaidAmount);

        ap.setPaidAmount(newPaidAmount);
        ap.setUnpaidAmount(newUnpaidAmount.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : newUnpaidAmount);
        if (newUnpaidAmount.compareTo(BigDecimal.ZERO) <= 0) {
            ap.setStatus(AccountsPayable.STATUS_PAID);
            ap.setPaidDate(LocalDate.now());
        } else {
            ap.setStatus(AccountsPayable.STATUS_PARTIAL);
        }
        ap.setUpdateTime(LocalDateTime.now());
        apRepository.updateById(ap);

        log.info("[财务] 付款确认完成 paymentNo={}, apNo={}, amount={}, unpaidAmount={}",
                paymentNo, ap.getApNo(), request.getAmount(), ap.getUnpaidAmount());

        return payment;
    }

    @Override
    public IPage<AccountsPayable> query(AccountsPayableQueryRequest request) {
        Page<AccountsPayable> page = new Page<>(request.getPage(), request.getPageSize());
        return apRepository.selectPageList(page,
                request.getApNo(), request.getPurchaseOrderNo(),
                request.getSupplierId(), request.getStatus(),
                null, null);
    }

    @Override
    public AccountsPayable getByApNo(String apNo) {
        return apRepository.findByApNo(apNo);
    }

    @Override
    public AccountsPayable getByPurchaseOrderNo(String purchaseOrderNo) {
        return apRepository.findByPurchaseOrderNo(purchaseOrderNo);
    }

    @Override
    public BigDecimal getTotalUnpaid() {
        BigDecimal amount = apRepository.sumTotalUnpaid();
        return amount != null ? amount : BigDecimal.ZERO;
    }

    @Override
    public BigDecimal getOverdueAmount(LocalDate date) {
        BigDecimal amount = apRepository.sumOverdueAmount(date);
        return amount != null ? amount : BigDecimal.ZERO;
    }

    private String generateApNo() {
        String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        return "AP" + date + String.format("%05d", AP_COUNTER.incrementAndGet());
    }

    private String generatePaymentNo() {
        String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        return "PAY" + date + String.format("%05d", System.currentTimeMillis() % 100000);
    }
}
