package com.erp.finance.controller;

import com.erp.finance.dto.*;
import com.erp.finance.entity.RefundRecord;
import com.erp.finance.entity.IncomeRecord;
import com.erp.finance.service.RefundService;
import com.erp.finance.service.IncomeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import com.erp.common.core.model.ApiResponse;

/**
 * 售后-财务联动控制器
 * 提供给 aftersale-service 调用的财务联动接口
 */
@Slf4j
@RestController
@RequestMapping("/api/finance/linkage/aftersale")
@RequiredArgsConstructor
public class AfterSalesFinanceLinkageController {

    private final RefundService refundService;
    private final IncomeService incomeService;

    /**
     * 售后退款发起 → 创建退款记录（待确认）
     * aftersale-service 审核通过售后退款后调用此接口
     */
    @PostMapping("/refund/create")
    public FinanceApiResponse<RefundRecordResponse> createAfterSaleRefund(@RequestBody RefundService.RefundCreateRequest request) {
        try {
            log.info("[售后联动] 创建售后退款 orderNo={}, amount={}, sourceId={}, source={}",
                    request.getOrderNo(), request.getRefundAmount(), request.getSourceId(), request.getSource());
            request.setType(RefundRecord.TYPE_AFTERSALE_REFUND);
            request.setSource(RefundRecord.SOURCE_AFTERSALE);
            RefundRecord record = refundService.createRefundRecord(request);
            return FinanceApiResponse.success("售后退款记录创建成功", toRefundResponse(record));
        } catch (Exception e) {
            log.error("[售后联动] 创建售后退款失败 orderNo={}", request.getOrderNo(), e);
            return FinanceApiResponse.error(500, "创建售后退款记录失败: " + e.getMessage());
        }
    }

    /**
     * 售后退款确认 → 财务确认退款
     * aftersale-service 确认售后退款后调用此接口
     */
    @PutMapping("/refund/{id}/confirm")
    public FinanceApiResponse<RefundRecordResponse> confirmAfterSaleRefund(@PathVariable Long id,
                                                                             @RequestParam(required = false) String operator) {
        try {
            log.info("[售后联动] 确认售后退款 id={}, operator={}", id, operator);
            RefundRecord record = refundService.confirmRefund(id, operator);
            return FinanceApiResponse.success("售后退款已确认", toRefundResponse(record));
        } catch (Exception e) {
            log.error("[售后联动] 确认售后退款失败 id={}", id, e);
            return FinanceApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 售后退款完成 → 更新退款状态（外部支付渠道回调）
     * aftersale-service 收到支付渠道退款成功回调后调用此接口
     */
    @PutMapping("/refund/{id}/complete")
    public FinanceApiResponse<RefundRecordResponse> completeAfterSaleRefund(@PathVariable Long id,
                                                                            @RequestParam String externalRefundNo,
                                                                            @RequestParam(required = false) String operator) {
        try {
            log.info("[售后联动] 完成售后退款 id={}, externalRefundNo={}", id, externalRefundNo);
            RefundRecord record = refundService.completeRefund(id, externalRefundNo, operator);
            return FinanceApiResponse.success("售后退款已完成", toRefundResponse(record));
        } catch (Exception e) {
            log.error("[售后联动] 完成售后退款失败 id={}", id, e);
            return FinanceApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 售后退款失败 → 标记退款失败
     */
    @PutMapping("/refund/{id}/fail")
    public FinanceApiResponse<?> failAfterSaleRefund(@PathVariable Long id,
                                                      @RequestParam String reason) {
        try {
            log.info("[售后联动] 售后退款失败 id={}, reason={}", id, reason);
            refundService.failRefund(id, reason);
            return FinanceApiResponse.success("退款失败已标记");
        } catch (Exception e) {
            log.error("[售后联动] 标记售后退款失败 id={}", id, e);
            return FinanceApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 售后退款取消
     */
    @PutMapping("/refund/{id}/cancel")
    public FinanceApiResponse<?> cancelAfterSaleRefund(@PathVariable Long id,
                                                        @RequestParam String reason,
                                                        @RequestParam(required = false) String operator) {
        try {
            log.info("[售后联动] 取消售后退款 id={}, reason={}", id, reason);
            refundService.cancelRefund(id, reason, operator);
            return FinanceApiResponse.success("售后退款已取消");
        } catch (Exception e) {
            log.error("[售后联动] 取消售后退款失败 id={}", id, e);
            return FinanceApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 根据售后单ID查询退款记录
     */
    @GetMapping("/refund/source/{sourceId}")
    public FinanceApiResponse<RefundRecordResponse> getRefundBySourceId(@PathVariable Long sourceId) {
        try {
            log.info("[售后联动] 根据sourceId查询退款 sourceId={}", sourceId);
            RefundRecord record = refundService.getById(sourceId);
            if (record == null) {
                return FinanceApiResponse.notFound("未找到对应的退款记录");
            }
            return FinanceApiResponse.success(toRefundResponse(record));
        } catch (Exception e) {
            log.error("[售后联动] 查询退款记录失败 sourceId={}", sourceId, e);
            return FinanceApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 查询订单对应的原收款记录（用于计算可退款金额）
     */
    @GetMapping("/income/{orderNo}")
    public FinanceApiResponse<IncomeRecordResponse> getIncomeByOrderNo(@PathVariable String orderNo) {
        try {
            log.info("[售后联动] 查询订单收款记录 orderNo={}", orderNo);
            IncomeRecord income = incomeService.getByOrderNo(orderNo);
            if (income == null) {
                return FinanceApiResponse.notFound("未找到订单对应的收款记录: " + orderNo);
            }
            return FinanceApiResponse.success(toIncomeResponse(income));
        } catch (Exception e) {
            log.error("[售后联动] 查询收款记录失败 orderNo={}", orderNo, e);
            return FinanceApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 售后退款汇总查询（按订单号）
     */
    @GetMapping("/summary/{orderNo}")
    public FinanceApiResponse<Map<String, Object>> getAfterSaleSummary(@PathVariable String orderNo) {
        try {
            log.info("[售后联动] 查询售后财务汇总 orderNo={}", orderNo);
            IncomeRecord income = incomeService.getByOrderNo(orderNo);
            Map<String, Object> summary = new HashMap<>();
            summary.put("orderNo", orderNo);
            if (income != null) {
                summary.put("incomeNo", income.getIncomeNo());
                summary.put("incomeAmount", income.getActualAmount());
                summary.put("incomeStatus", income.getStatus());
                summary.put("incomeRecordId", income.getId());
            } else {
                summary.put("incomeNo", null);
                summary.put("incomeAmount", BigDecimal.ZERO);
            }
            summary.put("hasIncomeRecord", income != null);
            return FinanceApiResponse.success(summary);
        } catch (Exception e) {
            log.error("[售后联动] 查询售后财务汇总失败 orderNo={}", orderNo, e);
            return FinanceApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 批量查询售后退款状态
     */
    @PostMapping("/refund/batch-query")
    public FinanceApiResponse<Map<Long, RefundRecordResponse>> batchQueryRefund(@RequestBody java.util.List<Long> sourceIds) {
        try {
            log.info("[售后联动] 批量查询退款状态 sourceIds={}", sourceIds.size());
            Map<Long, RefundRecordResponse> result = new HashMap<>();
            for (Long sourceId : sourceIds) {
                RefundRecord r = refundService.getById(sourceId);
                if (r != null) {
                    result.put(sourceId, toRefundResponse(r));
                }
            }
            return FinanceApiResponse.success(result);
        } catch (Exception e) {
            log.error("[售后联动] 批量查询退款状态失败", e);
            return FinanceApiResponse.error(500, e.getMessage());
        }
    }

    private static RefundRecordResponse toRefundResponse(RefundRecord r) {
        return RefundRecordResponse.builder()
                .id(r.getId())
                .refundNo(r.getRefundNo())
                .orderNo(r.getOrderNo())
                .shortId(r.getShortId())
                .refundAmount(r.getRefundAmount())
                .refundReason(r.getRefundReason())
                .refundTime(r.getRefundTime())
                .incomeRecordId(r.getIncomeRecordId())
                .originalAmount(r.getOriginalAmount())
                .refundMethod(r.getRefundMethod())
                .refundAccount(r.getRefundAccount())
                .status(r.getStatus())
                .type(r.getType())
                .sourceId(r.getSourceId())
                .source(r.getSource())
                .operator(r.getOperator())
                .completeTime(r.getCompleteTime())
                .failReason(r.getFailReason())
                .externalRefundNo(r.getExternalRefundNo())
                .remark(r.getRemark())
                .createTime(r.getCreateTime())
                .build();
    }

    private static IncomeRecordResponse toIncomeResponse(IncomeRecord r) {
        return IncomeRecordResponse.builder()
                .id(r.getId())
                .incomeNo(r.getIncomeNo())
                .orderNo(r.getOrderNo())
                .shortId(r.getShortId())
                .platform(r.getPlatform())
                .shopId(r.getShopId())
                .shopName(r.getShopName())
                .amount(r.getAmount())
                .discountAmount(r.getDiscountAmount())
                .actualAmount(r.getActualAmount())
                .paymentMethod(r.getPaymentMethod())
                .paymentTime(r.getPaymentTime())
                .transactionId(r.getTransactionId())
                .accountNo(r.getAccountNo())
                .accountName(r.getAccountName())
                .status(r.getStatus())
                .source(r.getSource())
                .remark(r.getRemark())
                .createTime(r.getCreateTime())
                .build();
    }
}
