import { Injectable, Logger } from '@nestjs/common';
import { EffectiveQuotaService } from './effective-quota.service';

/**
 * M-MEMBER-01-08: QuotaGuardService
 *
 * 为 13 项业务能力提供统一的额度检查入口。
 * 每个能力独立支持 legacy/shadow/enforced。
 */

export interface QuotaCheckResult {
  allowed: boolean;
  quotaType: string;
  limit: number;
  used: number;
  remaining: number;
  resetAt: string | null;
  upgradeAvailable: boolean;
}

export interface QuotaErrorResponse {
  errorCode: string;
  message: string;
  quotaType: string;
  limit: number;
  used: number;
  remaining: number;
  resetAt: string | null;
  upgradeAvailable: boolean;
}

@Injectable()
export class QuotaGuardService {
  private readonly logger = new Logger(QuotaGuardService.name);

  constructor(private readonly quotaService: EffectiveQuotaService) {}

  /**
   * 检查用户某项额度。
   *
   * @returns { allowed, quotaType, limit, used, remaining }
   *   allowed=false 时调用方应抛出 QuotaExceededException。
   */
  async check(
    userId: string,
    quotaType: string,
    operationId: string,
    amount: number = 1,
  ): Promise<QuotaCheckResult> {
    const result = await this.quotaService.reserve(userId, quotaType, operationId, amount);

    const resetAt = this.computeResetAt(quotaType);

    return {
      allowed: result.allowed,
      quotaType: result.quotaType,
      limit: result.limit,
      used: result.used,
      remaining: result.remaining,
      resetAt,
      upgradeAvailable: result.limit > 0 && !result.allowed,
    };
  }

  /**
   * 成功结算后确认额度。
   */
  async confirm(operationId: string) {
    await this.quotaService.commit(operationId);
  }

  /**
   * 失败/取消时释放预占。
   */
  async cancel(operationId: string) {
    await this.quotaService.release(operationId);
  }

  /**
   * 构建统一错误响应。
   */
  buildError(result: QuotaCheckResult): QuotaErrorResponse {
    const errorCode = this.errorCodeForType(result.quotaType);
    return {
      errorCode,
      message: `${result.quotaType} quota exceeded (${result.used}/${result.limit})`,
      quotaType: result.quotaType,
      limit: result.limit,
      used: result.used,
      remaining: result.remaining,
      resetAt: result.resetAt,
      upgradeAvailable: result.upgradeAvailable,
    };
  }

  // ── Private ──

  private errorCodeForType(quotaType: string): string {
    switch (quotaType) {
      case 'storage_bytes':
        return 'STORAGE_LIMIT_EXCEEDED';
      case 'knowledge_base_count':
        return 'KNOWLEDGE_BASE_LIMIT_EXCEEDED';
      case 'file_size_bytes':
        return 'FILE_SIZE_LIMIT_EXCEEDED';
      default:
        return 'QUOTA_EXCEEDED';
    }
  }

  private computeResetAt(quotaType: string): string | null {
    const now = new Date();
    switch (quotaType) {
      case 'active_recall':
      case 'feynman_evaluation':
      case 'quiz_generation':
      case 'learning_analysis_manual':
      case 'flashcard_generation': {
        const tomorrow = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1, -8, 0, 0));
        return tomorrow.toISOString();
      }
      case 'ai_chat_messages':
      case 'ocr_pages':
      case 'vision_pages': {
        const nextMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1, -8, 0, 0));
        return nextMonth.toISOString();
      }
      default:
        return null; // lifetime
    }
  }
}
