import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
  ForbiddenException,
  Logger,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { PrePlantingClient } from './pre-planting.client';

/**
 * 预种提现限制拦截器
 *
 * 仅拦截提现路由（POST /wallet/withdraw, /wallet/fiat-withdrawal）
 * 规则：
 * - 无预种记录（纯认种用户）→ 直接放行
 * - 有预种记录且已合并成树 → 放行
 * - 有预种记录但未合并 → 拦截提现
 * - SMS 验证码发送和取消操作不拦截
 * - planting-service 不可达 → 放行（fail-open）
 */
@Injectable()
export class PrePlantingWithdrawalInterceptor implements NestInterceptor {
  private readonly logger = new Logger(PrePlantingWithdrawalInterceptor.name);

  constructor(private readonly client: PrePlantingClient) {}

  async intercept(
    context: ExecutionContext,
    next: CallHandler,
  ): Promise<Observable<unknown>> {
    const req = context.switchToHttp().getRequest();

    // 仅拦截 POST 请求
    if (req.method !== 'POST') {
      return next.handle();
    }

    const reqPath: string = req.path || req.url || '';

    // 排除 SMS 和取消操作
    if (reqPath.includes('/send-sms') || reqPath.includes('/cancel')) {
      return next.handle();
    }

    // 仅拦截提现路由
    const isWithdrawal =
      reqPath.endsWith('/wallet/withdraw') ||
      reqPath.endsWith('/wallet/fiat-withdrawal');
    if (!isWithdrawal) {
      return next.handle();
    }

    const accountSequence = req.user?.accountSequence;
    if (!accountSequence) {
      return next.handle();
    }

    try {
      const eligibility = await this.client.getEligibility(accountSequence);

      // 无预种记录 → 纯认种用户，直接放行
      if (!eligibility.hasPrePlanting) {
        return next.handle();
      }

      // 有预种但未满足条件 → 拦截提现
      if (!eligibility.canTrade) {
        throw new ForbiddenException(
          '须累积购买5份预种计划合并成树后方可提现',
        );
      }
    } catch (error) {
      if (error instanceof ForbiddenException) throw error;
      // planting-service 不可达，默认放行
      this.logger.warn(
        `[PRE-PLANTING] Failed to check eligibility for ${accountSequence}, allowing through`,
      );
    }

    return next.handle();
  }
}
