import { supabase } from "@/db/supabase";

/**
 * Rate Limit Actions Enum
 */
export enum RateLimitAction {
  CREATE_TRIP = "create_trip",
  ADD_PLACE = "add_place",
  SEARCH = "search",
  EXPORT_PDF = "export_pdf",
  AI_SUGGESTION = "ai_suggestion",
}

export interface RateLimitStatus {
  allowed: boolean;
  remaining: number;
  limit: number;
  resetAt: Date | null;
  message?: string;
}

/**
 * Checks if a user has exceeded their rate limit for a specific action.
 * This method also increments the count as it uses the database function.
 * 
 * @param userId - The ID of the user
 * @param action - The action being performed
 * @returns Rate limit status
 */
export async function checkRateLimit(
  userId: string,
  action: RateLimitAction,
  limit?: number
): Promise<RateLimitStatus> {
  try {
    // @ts-ignore
    const { data, error } = await supabase.rpc("check_rate_limit", {
      p_user_id: userId,
      p_ip_address: null,
      p_endpoint: action,
    });

    if (error) {
      console.error("Rate limit check error:", error);
      return { allowed: true, remaining: 1, limit: limit || 1, resetAt: null };
    }

    const status = data as {
      allowed: boolean;
      remaining: number;
      limit: number;
      reset_at: string;
      window_seconds: number;
    };

    // If a manual limit was provided, we adjust the 'allowed' status based on it
    // though the DB has already logged the request. 
    // Usually, it's better to rely on DB rules.
    const effectiveAllowed = limit !== undefined ? status.remaining > 0 && (status.limit - status.remaining < limit) : status.allowed;

    return {
      allowed: effectiveAllowed,
      remaining: status.remaining,
      limit: status.limit,
      resetAt: status.reset_at ? new Date(status.reset_at) : null,
      message: !effectiveAllowed ? getErrorMessage(action) : undefined,
    };
  } catch (err) {
    console.error("Rate limit check failed:", err);
    return { allowed: true, remaining: 1, limit: 1, resetAt: null };
  }
}

/**
 * Increments the request count for a user action.
 * (In this implementation, checkRateLimit already increments the count via SQL function)
 * If you need to manually increment without checking, you can call checkRateLimit and ignore the result.
 */
export async function incrementCount(userId: string, action: RateLimitAction): Promise<void> {
  await checkRateLimit(userId, action);
}

/**
 * Resets the request count for a user action by deleting logs.
 */
export async function resetCount(userId: string, action: RateLimitAction): Promise<void> {
  const { error } = await supabase
    .from("rate_limit_logs")
    .delete()
    .match({ user_id: userId, endpoint: action });

  if (error) {
    console.error("Rate limit reset error:", error);
  }
}

/**
 * Gets the current status of a user's rate limit without necessarily incrementing it.
 * Note: The current database function `check_rate_limit` ALWAYS increments.
 * To get status WITHOUT incrementing, we query the logs directly.
 */
export async function getStatus(userId: string, action: RateLimitAction): Promise<RateLimitStatus> {
  try {
    // Get rule first
    const { data: ruleData, error: ruleError } = await supabase
      .from("rate_limit_rules")
      .select("*")
      .eq("endpoint", action)
      .eq("enabled", true)
      .maybeSingle();

    if (ruleError || !ruleData) {
      return { allowed: true, remaining: 999, limit: 999, resetAt: null };
    }

    const rule = ruleData as { window_seconds: number; max_requests: number };
    const windowStart = new Date(Date.now() - rule.window_seconds * 1000).toISOString();

    const { data: logsData, error } = await supabase
      .from("rate_limit_logs")
      .select("request_count")
      .eq("user_id", userId)
      .eq("endpoint", action)
      .gte("window_start", windowStart);

    if (error) throw error;

    const logs = (logsData || []) as { request_count: number }[];
    const totalRequests = logs.reduce((acc, log) => acc + log.request_count, 0);
    const remaining = Math.max(0, rule.max_requests - totalRequests);
    const resetAt = new Date(Date.now() + rule.window_seconds * 1000);

    return {
      allowed: remaining > 0,
      remaining,
      limit: rule.max_requests,
      resetAt,
      message: remaining === 0 ? getErrorMessage(action) : undefined,
    };
  } catch (err) {
    console.error("Get rate limit status failed:", err);
    return { allowed: true, remaining: 1, limit: 1, resetAt: null };
  }
}

function getErrorMessage(action: RateLimitAction): string {
  switch (action) {
    case RateLimitAction.CREATE_TRIP:
      return "Çok fazla gezi planı oluşturdunuz. Lütfen daha sonra tekrar deneyin.";
    case RateLimitAction.ADD_PLACE:
      return "Kısa sürede çok fazla yer eklediniz. Lütfen biraz bekleyin.";
    case RateLimitAction.SEARCH:
      return "Arama limitinize ulaştınız. Lütfen birkaç dakika bekleyin.";
    case RateLimitAction.EXPORT_PDF:
      return "Günlük PDF dışa aktarma limitinize ulaştınız.";
    case RateLimitAction.AI_SUGGESTION:
      return "Yapay zeka öneri limitinize ulaştınız. Lütfen daha sonra tekrar deneyin.";
    default:
      return "İşlem limitine ulaşıldı. Lütfen daha sonra tekrar deneyin.";
  }
}
