package com.starry.admin.modules.withdraw.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.starry.admin.common.exception.CustomException;
import com.starry.admin.modules.withdraw.entity.ClerkPayeeProfileEntity;
import com.starry.admin.modules.withdraw.entity.EarningsLineEntity;
import com.starry.admin.modules.withdraw.entity.WithdrawalRequestEntity;
import com.starry.admin.modules.withdraw.mapper.WithdrawalRequestMapper;
import com.starry.admin.modules.withdraw.service.IClerkPayeeProfileService;
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.PayeeSnapshotVo;
import com.starry.admin.utils.SecurityUtils;
import com.starry.common.utils.IdUtils;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

@Service
public class WithdrawalServiceImpl extends ServiceImpl<WithdrawalRequestMapper, WithdrawalRequestEntity>
        implements IWithdrawalService {

    @Resource
    private IEarningsService earningsService;
    @Resource
    private IWithdrawalLogService withdrawalLogService;
    @Resource
    private IClerkPayeeProfileService clerkPayeeProfileService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WithdrawalRequestEntity createWithdrawaRequest(String clerkId, BigDecimal amount) {
        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new CustomException("提现金额必须大于0");
        }
        LocalDateTime now = LocalDateTime.now();
        String tenantId = SecurityUtils.getTenantId();
        ClerkPayeeProfileEntity payeeProfile = clerkPayeeProfileService.getByClerk(tenantId, clerkId);
        if (payeeProfile == null || !StringUtils.hasText(payeeProfile.getQrCodeUrl())) {
            throw new CustomException("请先上传支付宝收款码");
        }

        if (payeeProfile.getLastConfirmedAt() == null) {
            throw new CustomException("请确认本次使用的收款码");
        }

        // pick and reserve lines
        List<EarningsLineEntity> lines = earningsService.findWithdrawable(clerkId, amount, now);
        if (lines.isEmpty()) {
            BigDecimal latestAvailable = earningsService.getAvailableAmount(clerkId, now);
            throw new CustomException("可提现余额不足或已被锁定，当前可用：" + latestAvailable);
        }

        // Reserve lines FIRST with temp ID (fail fast before creating request)
        String tempWithdrawalId = "TEMP_" + IdUtils.getUuid();
        int reservedCount = 0;
        for (EarningsLineEntity line : lines) {
            boolean updated = earningsService.update(Wrappers.lambdaUpdate(EarningsLineEntity.class)
                    .eq(EarningsLineEntity::getId, line.getId())
                    .eq(EarningsLineEntity::getStatus, line.getStatus()) // Verify status unchanged
                    .set(EarningsLineEntity::getStatus, "withdrawing")
                    .set(EarningsLineEntity::getWithdrawalId, tempWithdrawalId));
            if (!updated) {
                // Another request already took this line
                throw new CustomException("部分收益已被其他提现请求锁定，请重试");
            }
            reservedCount++;
        }

        // Only NOW create the request (after successful reservation)
        LocalDateTime confirmedAt = payeeProfile.getLastConfirmedAt();
        String snapshotJson = buildPayeeSnapshot(payeeProfile, confirmedAt);

        WithdrawalRequestEntity req = new WithdrawalRequestEntity();
        req.setId(IdUtils.getUuid());
        req.setClerkId(clerkId);
        req.setTenantId(tenantId);
        req.setAmount(amount);
        req.setFee(BigDecimal.ZERO); // fee on tenant; not deducted from clerk
        req.setNetAmount(amount);
        req.setDestAccount(payeeProfile.getDisplayName());
        req.setPayeeSnapshot(snapshotJson);
        req.setStatus("pending");
        req.setOutBizNo(req.getId());
        this.save(req);

        // Update temp ID to real ID
        earningsService.update(Wrappers.lambdaUpdate(EarningsLineEntity.class)
                .eq(EarningsLineEntity::getWithdrawalId, tempWithdrawalId)
                .set(EarningsLineEntity::getWithdrawalId, req.getId()));

        // log created
        withdrawalLogService.log(req.getTenantId(), clerkId, req.getId(),
                "CREATED", null, req.getStatus(), "提现申请创建", null);
        withdrawalLogService.log(req.getTenantId(), clerkId, req.getId(),
                "PAYEE_CONFIRMED", req.getStatus(), req.getStatus(), "店员确认收款码", snapshotJson);
        withdrawalLogService.log(req.getTenantId(), clerkId, req.getId(),
                "RESERVED", req.getStatus(), req.getStatus(),
                "冻结收益已预留，条数=" + reservedCount + ", 金额=" + amount, null);

        // reset confirmation to force next withdrawal to re-confirm
        payeeProfile.setLastConfirmedAt(null);
        payeeProfile.setUpdatedBy(clerkId);
        clerkPayeeProfileService.updateById(payeeProfile);

        // 自动打款未实现，等待运营手动处理
        return req;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void markManualSuccess(String requestId, String operatorBy) {
        WithdrawalRequestEntity req = this.getById(requestId);
        if (req == null) throw new CustomException("请求不存在");
        if (!"pending".equals(req.getStatus()) && !"processing".equals(req.getStatus())) {
            throw new CustomException("当前状态不可操作");
        }
        WithdrawalRequestEntity update = new WithdrawalRequestEntity();
        update.setId(req.getId());
        update.setStatus("success");
        this.updateById(update);

        // Set reserved earnings lines to withdrawn
        earningsService.update(Wrappers.lambdaUpdate(EarningsLineEntity.class)
                .eq(EarningsLineEntity::getWithdrawalId, req.getId())
                .eq(EarningsLineEntity::getStatus, "withdrawing")
                .set(EarningsLineEntity::getStatus, "withdrawn"));

        withdrawalLogService.log(req.getTenantId(), req.getClerkId(), req.getId(),
                "PAYOUT_SUCCESS", req.getStatus(), "success",
                "手动打款成功，操作人=" + operatorBy, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void autoPayout(String requestId) {
        WithdrawalRequestEntity req = this.getById(requestId);
        if (req == null) throw new CustomException("请求不存在");
        if (!"pending".equals(req.getStatus())) {
            throw new CustomException("当前状态不可自动打款");
        }
        // Transition to processing and log
        WithdrawalRequestEntity update = new WithdrawalRequestEntity();
        update.setId(req.getId());
        update.setStatus("processing");
        this.updateById(update);
        withdrawalLogService.log(req.getTenantId(), req.getClerkId(), req.getId(),
                "PAYOUT_REQUESTED", req.getStatus(), "processing",
                "发起支付宝打款（未实现）", null);

        // Not implemented yet
        throw new UnsupportedOperationException("Alipay payout not implemented");
    }

    private String buildPayeeSnapshot(ClerkPayeeProfileEntity profile, LocalDateTime confirmedAt) {
        PayeeSnapshotVo snapshot = new PayeeSnapshotVo();
        snapshot.setChannel(profile.getChannel());
        snapshot.setQrCodeUrl(profile.getQrCodeUrl());
        snapshot.setDisplayName(profile.getDisplayName());
        snapshot.setConfirmedAt(confirmedAt);
        return JSON.toJSONString(snapshot);
    }
}
