package com.starry.admin.modules.withdraw.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.starry.admin.common.aspect.ClerkUserLogin;
import com.starry.admin.common.conf.ThreadLocalRequestDetail;
import com.starry.admin.common.exception.CustomException;
import com.starry.admin.modules.order.module.entity.PlayOrderInfoEntity;
import com.starry.admin.modules.order.service.IPlayOrderInfoService;
import com.starry.admin.modules.withdraw.entity.EarningsLineEntity;
import com.starry.admin.modules.withdraw.entity.WithdrawalLogEntity;
import com.starry.admin.modules.withdraw.entity.WithdrawalRequestEntity;
import com.starry.admin.modules.withdraw.service.IEarningsService;
import com.starry.admin.modules.withdraw.service.IWithdrawalLogService;
import com.starry.admin.modules.withdraw.service.IWithdrawalService;
import com.starry.admin.modules.withdraw.vo.ClerkEarningLineVo;
import com.starry.admin.modules.withdraw.vo.ClerkWithdrawBalanceVo;
import com.starry.common.result.TypedR;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
@RequestMapping("/wx/withdraw")
public class WxWithdrawController {

    @Resource
    private IEarningsService earningsService;
    @Resource
    private IWithdrawalService withdrawalService;
    @Resource
    private IWithdrawalLogService withdrawalLogService;
    @Resource
    private IPlayOrderInfoService orderInfoService;

    @Data
    public static class CreateWithdrawRequest {
        private BigDecimal amount;
    }

    @ClerkUserLogin
    @GetMapping("/balance")
    public TypedR<ClerkWithdrawBalanceVo> getBalance() {
        String clerkId = ThreadLocalRequestDetail.getClerkUserInfo().getId();
        LocalDateTime now = LocalDateTime.now();
        BigDecimal available = earningsService.getAvailableAmount(clerkId, now);
        BigDecimal pending = earningsService.getPendingAmount(clerkId, now);
        LocalDateTime nextUnlock = earningsService.getNextUnlockTime(clerkId, now);
        return TypedR.ok(new ClerkWithdrawBalanceVo(available, pending, nextUnlock));
    }

    @ClerkUserLogin
    @GetMapping("/earnings")
    public TypedR<java.util.List<ClerkEarningLineVo>> listEarnings(
            @RequestParam(value = "status", required = false) String status,
            @RequestParam(value = "pageNum", defaultValue = "1") long pageNum,
            @RequestParam(value = "pageSize", defaultValue = "10") long pageSize,
            @RequestParam(value = "beginTime", required = false) String beginTime,
            @RequestParam(value = "endTime", required = false) String endTime) {
        String clerkId = ThreadLocalRequestDetail.getClerkUserInfo().getId();
        LambdaQueryWrapper<EarningsLineEntity> q = new LambdaQueryWrapper<>();
        q.eq(EarningsLineEntity::getClerkId, clerkId);
        if (status != null && !status.isEmpty()) {
            q.eq(EarningsLineEntity::getStatus, status);
        }
        LocalDateTime begin = parseDateTime(beginTime);
        LocalDateTime end = parseDateTime(endTime);
        if (begin != null) {
            q.ge(EarningsLineEntity::getCreatedTime, begin);
        }
        if (end != null) {
            q.le(EarningsLineEntity::getCreatedTime, end);
        }
        q.orderByDesc(EarningsLineEntity::getCreatedTime);
        IPage<EarningsLineEntity> page = earningsService.page(new Page<>(pageNum, pageSize), q);

        List<EarningsLineEntity> records = page.getRecords();
        List<ClerkEarningLineVo> vos = new ArrayList<>();
        if (!records.isEmpty()) {
            List<String> orderIds = records.stream()
                    .map(EarningsLineEntity::getOrderId)
                    .filter(id -> id != null && !id.isEmpty())
                    .distinct()
                    .collect(Collectors.toList());
            Map<String, PlayOrderInfoEntity> orderMap = orderIds.isEmpty() ? java.util.Collections.emptyMap()
                    : orderInfoService.lambdaQuery()
                            .in(PlayOrderInfoEntity::getId, orderIds)
                            .list()
                            .stream()
                            .collect(Collectors.toMap(PlayOrderInfoEntity::getId, it -> it));
            for (EarningsLineEntity line : records) {
                ClerkEarningLineVo vo = new ClerkEarningLineVo();
                vo.setId(line.getId());
                vo.setAmount(line.getAmount());
                vo.setStatus(line.getStatus());
                vo.setEarningType(line.getEarningType());
                vo.setWithdrawalId(line.getWithdrawalId());
                vo.setUnlockTime(line.getUnlockTime());
                vo.setCreatedTime(toLocalDateTime(line.getCreatedTime()));
                vo.setOrderId(line.getOrderId());
                if (line.getOrderId() != null) {
                    PlayOrderInfoEntity order = orderMap.get(line.getOrderId());
                    if (order != null) {
                        vo.setOrderNo(order.getOrderNo());
                        vo.setOrderStatus(order.getOrderStatus());
                        vo.setOrderEndTime(toLocalDateTime(order.getOrderEndTime()));
                    }
                }
                vos.add(vo);
            }
        }
        Page<ClerkEarningLineVo> result = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        long totalPage = page.getSize() == 0 ? 0 : (long) Math.ceil((double) page.getTotal() / (double) page.getSize());
        result.setPages(totalPage);
        result.setRecords(vos);
        return TypedR.okPage(result);
    }

    @ClerkUserLogin
    @PostMapping("/requests")
    public TypedR<WithdrawalRequestEntity> createWithdraw(@RequestBody CreateWithdrawRequest body) {
        if (body.getAmount() == null || body.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new CustomException("提现金额必须大于0");
        }
        String clerkId = ThreadLocalRequestDetail.getClerkUserInfo().getId();
        WithdrawalRequestEntity req = withdrawalService.createWithdrawaRequest(clerkId, body.getAmount());
        return TypedR.ok(req);
    }

    @ClerkUserLogin
    @GetMapping("/requests")
    public TypedR<java.util.List<WithdrawalRequestEntity>> listRequests(@RequestParam(value = "pageNum", defaultValue = "1") long pageNum,
                          @RequestParam(value = "pageSize", defaultValue = "10") long pageSize) {
        String clerkId = ThreadLocalRequestDetail.getClerkUserInfo().getId();
        LambdaQueryWrapper<WithdrawalRequestEntity> q = new LambdaQueryWrapper<>();
        q.eq(WithdrawalRequestEntity::getClerkId, clerkId).orderByDesc(WithdrawalRequestEntity::getCreatedTime);
        IPage<WithdrawalRequestEntity> page = withdrawalService.page(new Page<>(pageNum, pageSize), q);
        return TypedR.okPage(page);
    }

    @ClerkUserLogin
    @GetMapping("/requests/{id}/logs")
    public TypedR<java.util.List<WithdrawalLogEntity>> getRequestLogs(@PathVariable("id") String id) {
        String clerkId = ThreadLocalRequestDetail.getClerkUserInfo().getId();
        WithdrawalRequestEntity req = withdrawalService.getById(id);
        if (req == null || !clerkId.equals(req.getClerkId())) {
            throw new CustomException("无权查看");
        }
        java.util.List<WithdrawalLogEntity> list = withdrawalLogService.lambdaQuery()
                .eq(WithdrawalLogEntity::getWithdrawalId, id)
                .orderByAsc(WithdrawalLogEntity::getCreatedTime)
                .list();
        return TypedR.ok(list);
    }

    private LocalDateTime parseDateTime(String value) {
        if (value == null || value.trim().isEmpty()) {
            return null;
        }
        String trimmed = value.trim();
        DateTimeFormatter[] formatters = new DateTimeFormatter[] {
                DateTimeFormatter.ISO_DATE_TIME,
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"),
                DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")
        };
        for (DateTimeFormatter formatter : formatters) {
            try {
                return LocalDateTime.parse(trimmed, formatter);
            } catch (DateTimeParseException ignored) {
            }
        }
        return null;
    }

    private LocalDateTime toLocalDateTime(Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof LocalDateTime) {
            return (LocalDateTime) value;
        }
        if (value instanceof Date) {
            return ((Date) value).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        }
        return null;
    }
}
