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.RefundQueryRequest;
import com.erp.finance.entity.RefundRecord;
import com.erp.finance.repository.RefundRecordRepository;
import com.erp.finance.service.RefundService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

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 RefundServiceImpl implements RefundService {

    private final RefundRecordRepository refundRecordRepository;
    private static final AtomicLong REFUND_COUNTER = new AtomicLong(System.currentTimeMillis() % 100000);

    @Override
    @Transactional
    public RefundRecord createRefundRecord(RefundCreateRequest request) {
        log.info("[财务] 创建退款记录 orderNo={}, amount={}, type={}, source={}",
                request.getOrderNo(), request.getRefundAmount(), request.getType(), request.getSource());

        // 检查是否已存在（防止重复）
        if (request.getSourceId() != null && StringUtils.hasText(request.getSource())) {
            RefundRecord existing = refundRecordRepository.findBySourceId(request.getSourceId(), request.getSource());
            if (existing != null) {
                log.warn("[财务] 退款记录已存在 sourceId={}, source={}, refundNo={}",
                        request.getSourceId(), request.getSource(), existing.getRefundNo());
                return existing;
            }
        }

        String refundNo = generateRefundNo();
        LocalDateTime refundTime = request.getRefundTime() != null ? request.getRefundTime() : LocalDateTime.now();

        RefundRecord record = RefundRecord.builder()
                .refundNo(refundNo)
                .orderNo(request.getOrderNo())
                .shortId(request.getShortId())
                .refundAmount(request.getRefundAmount())
                .refundReason(request.getRefundReason())
                .refundTime(refundTime)
                .incomeRecordId(request.getIncomeRecordId())
                .originalAmount(request.getOriginalAmount())
                .refundMethod(StringUtils.hasText(request.getRefundMethod()) ? request.getRefundMethod() : "original")
                .refundAccount(request.getRefundAccount())
                .status(RefundRecord.STATUS_PENDING)
                .type(request.getType())
                .sourceId(request.getSourceId())
                .source(request.getSource())
                .operator(request.getOperator())
                .remark(request.getRemark())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .deleted(0)
                .build();

        refundRecordRepository.insert(record);
        log.info("[财务] 退款记录创建成功 refundNo={}, orderNo={}, amount={}",
                refundNo, request.getOrderNo(), request.getRefundAmount());
        return record;
    }

    @Override
    @Transactional
    public RefundRecord confirmRefund(Long id, String operator) {
        RefundRecord record = refundRecordRepository.selectById(id);
        if (record == null) {
            throw new RuntimeException("退款记录不存在: " + id);
        }
        if (!RefundRecord.STATUS_PENDING.equals(record.getStatus())) {
            throw new RuntimeException("只有待处理状态的退款可以确认，当前状态: " + record.getStatus());
        }
        record.setStatus(RefundRecord.STATUS_PROCESSING);
        record.setOperator(operator);
        record.setUpdateTime(LocalDateTime.now());
        refundRecordRepository.updateById(record);
        log.info("[财务] 退款确认发起 refundNo={}, operator={}", record.getRefundNo(), operator);
        return record;
    }

    @Override
    @Transactional
    public RefundRecord completeRefund(Long id, String externalRefundNo, String operator) {
        RefundRecord record = refundRecordRepository.selectById(id);
        if (record == null) {
            throw new RuntimeException("退款记录不存在: " + id);
        }
        if (!RefundRecord.STATUS_PROCESSING.equals(record.getStatus())) {
            throw new RuntimeException("只有处理中的退款可以完成，当前状态: " + record.getStatus());
        }
        record.setStatus(RefundRecord.STATUS_COMPLETED);
        record.setCompleteTime(LocalDateTime.now());
        record.setExternalRefundNo(externalRefundNo);
        record.setUpdateTime(LocalDateTime.now());
        refundRecordRepository.updateById(record);
        log.info("[财务] 退款完成 refundNo={}, externalRefundNo={}, operator={}",
                record.getRefundNo(), externalRefundNo, operator);
        return record;
    }

    @Override
    @Transactional
    public void failRefund(Long id, String reason) {
        RefundRecord record = refundRecordRepository.selectById(id);
        if (record == null) {
            throw new RuntimeException("退款记录不存在: " + id);
        }
        record.setStatus(RefundRecord.STATUS_FAILED);
        record.setFailReason(reason);
        record.setUpdateTime(LocalDateTime.now());
        refundRecordRepository.updateById(record);
        log.warn("[财务] 退款失败 refundNo={}, reason={}", record.getRefundNo(), reason);
    }

    @Override
    @Transactional
    public void cancelRefund(Long id, String reason, String operator) {
        RefundRecord record = refundRecordRepository.selectById(id);
        if (record == null) {
            throw new RuntimeException("退款记录不存在: " + id);
        }
        if (!RefundRecord.STATUS_PENDING.equals(record.getStatus())) {
            throw new RuntimeException("只有待处理的退款可以取消，当前状态: " + record.getStatus());
        }
        record.setStatus(RefundRecord.STATUS_FAILED);
        record.setFailReason("取消: " + reason);
        record.setUpdateTime(LocalDateTime.now());
        refundRecordRepository.updateById(record);
        log.info("[财务] 退款取消 refundNo={}, reason={}, operator={}", record.getRefundNo(), reason, operator);
    }

    @Override
    public IPage<RefundRecord> query(RefundQueryRequest request) {
        Page<RefundRecord> page = new Page<>(request.getPage(), request.getPageSize());
        LocalDateTime startDate = parseDate(request.getStartDate(), true);
        LocalDateTime endDate = parseDate(request.getEndDate(), false);
        return refundRecordRepository.selectPageList(page,
                request.getOrderNo(), request.getStatus(),
                request.getType(), startDate, endDate);
    }

    @Override
    public RefundRecord getById(Long id) {
        return refundRecordRepository.selectById(id);
    }

    @Override
    public RefundRecord getByRefundNo(String refundNo) {
        return refundRecordRepository.findByRefundNo(refundNo);
    }

    @Override
    public long getPendingCount() {
        return refundRecordRepository.countPendingRefunds();
    }

    @Override
    public BigDecimal sumCompletedRefundAmount(LocalDateTime startTime, LocalDateTime endTime) {
        BigDecimal amount = refundRecordRepository.sumCompletedRefundAmount(startTime, endTime);
        return amount != null ? amount : BigDecimal.ZERO;
    }

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

    private LocalDateTime parseDate(String dateStr, boolean startOfDay) {
        if (!StringUtils.hasText(dateStr)) return null;
        try {
            LocalDate date = LocalDate.parse(dateStr);
            return startOfDay ? date.atStartOfDay() : date.atTime(23, 59, 59);
        } catch (Exception e) {
            return null;
        }
    }
}
