package cn.novalon.gym.manage.member.handler;

import cn.hutool.db.PageResult;
import cn.novalon.gym.manage.member.entity.MemberCardTransaction;
import cn.novalon.gym.manage.member.enums.TransactionType;
import cn.novalon.gym.manage.member.service.IMemberCardTransactionService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Validator;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 会员卡流水管理处理器
 * 
 * @author 付嘉
 * @date 2026-05-27
 */
@Component
@Tag(name = "会员卡流水管理", description = "会员卡流水相关操作")
public class MemberCardTransactionHandler {

    private final IMemberCardTransactionService memberCardTransactionService;
    private final Validator validator;

    public MemberCardTransactionHandler(IMemberCardTransactionService memberCardTransactionService,
                                        Validator validator) {
        this.memberCardTransactionService = memberCardTransactionService;
        this.validator = validator;
    }

    /**
     * 记录每一次变动
     */
    @Operation(summary = "插入流水记录", description = "购卡、扣次、续费、退款、过期时插入流水")
    public Mono<ServerResponse> insertTransaction(ServerRequest request) {
        return request.bodyToMono(MemberCardTransaction.class)
                .flatMap(memberCardTransactionService::insertTransaction)
                .flatMap(record -> ServerResponse.ok().bodyValue(record));
    }

    /**
     * 会员端"使用记录"
     */
    @Operation(summary = "会员查询使用记录", description = "按会员ID和时间范围查询流水，支持分页")
    public Mono<ServerResponse> getMemberTransactions(ServerRequest request) {
        Long memberId = Long.parseLong(request.pathVariable("memberId"));
        LocalDateTime startTime = request.queryParam("startTime")
                .map(LocalDateTime::parse).orElse(LocalDateTime.now().minusMonths(1));
        LocalDateTime endTime = request.queryParam("endTime")
                .map(LocalDateTime::parse).orElse(LocalDateTime.now());
        int page = request.queryParam("page").map(Integer::parseInt).orElse(0);
        int size = request.queryParam("size").map(Integer::parseInt).orElse(10);
        Pageable pageable = PageRequest.of(page, size, Sort.by("created_at").descending());

        return ServerResponse.ok()
                .body(memberCardTransactionService.findByMemberIdAndTimeRange(
                        memberId, startTime, endTime, pageable), MemberCardTransaction.class);
    }

    /**
     * 后台"使用记录查询"（条件分页）
     */
    @Operation(summary = "管理端流水查询", description = "按会员、卡号、操作类型、时间等条件分页查询流水")
    public Mono<ServerResponse> getTransactionsWithConditions(ServerRequest request) {
        Long memberId = request.queryParam("memberId").map(Long::parseLong).orElse(null);
        Long memberCardId = request.queryParam("memberCardId").map(Long::parseLong).orElse(null);
        TransactionType operationType = request.queryParam("operationType")
                .map(s -> TransactionType.valueOf(s.toUpperCase())).orElse(null);
        LocalDateTime startTime = request.queryParam("startTime").map(LocalDateTime::parse).orElse(null);
        LocalDateTime endTime = request.queryParam("endTime").map(LocalDateTime::parse).orElse(null);
        int page = request.queryParam("page").map(Integer::parseInt).orElse(0);
        int size = request.queryParam("size").map(Integer::parseInt).orElse(10);
        Pageable pageable = PageRequest.of(page, size, Sort.by("created_at").descending());

        Mono<Long> countMono = memberCardTransactionService.countWithConditions(
                memberId, memberCardId, operationType, startTime, endTime);
        Flux<MemberCardTransaction> flux = memberCardTransactionService.findWithConditions(
                memberId, memberCardId, operationType, startTime, endTime, pageable);

        return Mono.zip(countMono, flux.collectList())
                .flatMap(tuple -> {
                    Long total = tuple.getT1();
                    List<MemberCardTransaction> list = tuple.getT2();
                    // 构造 PageResult，内部自动计算总页数
                    PageResult<MemberCardTransaction> result = new PageResult<>(page, size, total.intValue());
                    result.addAll(list);
                    return ServerResponse.ok().bodyValue(result);
                });
    }

    /**
     * 按卡ID查询流水
     */
    @Operation(summary = "按卡ID查询流水", description = "查看某张卡的所有流水记录")
    public Mono<ServerResponse> getTransactionsByCardId(ServerRequest request) {
        Long memberCardId = Long.parseLong(request.pathVariable("cardId"));
        return ServerResponse.ok()
                .body(memberCardTransactionService.findByMemberCardId(memberCardId),
                        MemberCardTransaction.class);
    }

    /**
     * 统计某卡种的总扣次数
     */
    @Operation(summary = "统计卡种总扣次数", description = "按卡种ID和时间范围统计扣次总数")
    public Mono<ServerResponse> getDeductCountByCardId(ServerRequest request) {
        Long memberCardId = Long.parseLong(request.pathVariable("cardId"));
        LocalDateTime startTime = request.queryParam("startTime")
                .map(LocalDateTime::parse).orElse(LocalDateTime.now().minusMonths(1));
        LocalDateTime endTime = request.queryParam("endTime")
                .map(LocalDateTime::parse).orElse(LocalDateTime.now());
        return memberCardTransactionService.sumDeductCountByCardId(memberCardId, startTime, endTime)
                .flatMap(count -> ServerResponse.ok().bodyValue(count));
    }

    /**
     * 统计某时间段的续费总金额
     */
    @Operation(summary = "统计续费总金额", description = "按时间段统计续费总金额")
    public Mono<ServerResponse> getRenewAmountByTimeRange(ServerRequest request) {
        LocalDateTime startTime = request.queryParam("startTime")
                .map(LocalDateTime::parse).orElse(LocalDateTime.now().minusMonths(1));
        LocalDateTime endTime = request.queryParam("endTime")
                .map(LocalDateTime::parse).orElse(LocalDateTime.now());
        return memberCardTransactionService.sumRenewAmountByTimeRange(startTime, endTime)
                .flatMap(amount -> ServerResponse.ok().bodyValue(amount));
    }

    /**
     * 统计某会员的购卡总金额
     */
    @Operation(summary = "统计会员购卡总金额", description = "按会员ID和时间段统计购卡总金额")
    public Mono<ServerResponse> getPurchaseAmountByMember(ServerRequest request) {
        Long memberId = Long.parseLong(request.pathVariable("memberId"));
        LocalDateTime startTime = request.queryParam("startTime")
                .map(LocalDateTime::parse).orElse(LocalDateTime.now().minusMonths(1));
        LocalDateTime endTime = request.queryParam("endTime")
                .map(LocalDateTime::parse).orElse(LocalDateTime.now());
        return memberCardTransactionService.sumPurchaseAmountByMemberId(memberId, startTime, endTime)
                .flatMap(amount -> ServerResponse.ok().bodyValue(amount));
    }
}
