import { redis } from "@/infrastructure/cache/redis";
import { RATE_LIMIT } from "@/config/constants";

const { MAX_REQUESTS: RATE_LIMIT_MAX, WINDOW_MS: RATE_LIMIT_WINDOW } = RATE_LIMIT;

export interface RateLimitResult {
  success: boolean;
  limit: number;
  remaining: number;
  resetTime: Date;
  identifier: string;
}

const getRateLimitKey = (identifier: string, type: "ip" | "phone"): string =>
  `ratelimit:${type}:${identifier}`;

export async function checkRateLimit(
  identifier: string,
  type: "ip" | "phone" = "ip"
): Promise<RateLimitResult> {
  const key = getRateLimitKey(identifier, type);
  const now = Date.now();
  const windowStart = now - RATE_LIMIT_WINDOW;

  try {
    // Get current request count
    const currentCount = await redis.zcard(key);

    // Remove old requests outside the window
    await redis.zremrangebyscore(key, 0, windowStart);

    // Get updated count after cleanup
    const updatedCount = await redis.zcard(key);

    if (updatedCount >= RATE_LIMIT_MAX) {
      // Rate limit exceeded
      const oldestRequest = await redis.zrange(key, 0, 0);
      const resetTime =
        oldestRequest.length > 0
          ? new Date(parseInt(oldestRequest[0]) + RATE_LIMIT_WINDOW)
          : new Date(now + RATE_LIMIT_WINDOW);

      return {
        success: false,
        limit: RATE_LIMIT_MAX,
        remaining: 0,
        resetTime,
        identifier,
      };
    }

    // Add current request
    await redis.zadd(key, now.toString(), now.toString());
    await redis.expire(key, Math.ceil(RATE_LIMIT_WINDOW / 1000));

    return {
      success: true,
      limit: RATE_LIMIT_MAX,
      remaining: RATE_LIMIT_MAX - updatedCount - 1,
      resetTime: new Date(now + RATE_LIMIT_WINDOW),
      identifier,
    };
  } catch (error) {
    console.error("Rate limit check error:", error);
    // Fail open: allow request if Redis fails
    return {
      success: true,
      limit: RATE_LIMIT_MAX,
      remaining: RATE_LIMIT_MAX,
      resetTime: new Date(now + RATE_LIMIT_WINDOW),
      identifier,
    };
  }
}

export async function resetRateLimit(
  identifier: string,
  type: "ip" | "phone" = "ip"
): Promise<void> {
  const key = getRateLimitKey(identifier, type);
  await redis.del(key);
}

export async function getRateLimitStatus(
  identifier: string,
  type: "ip" | "phone" = "ip"
): Promise<{ limit: number; remaining: number; resetTime: Date }> {
  const key = getRateLimitKey(identifier, type);
  const now = Date.now();
  const windowStart = now - RATE_LIMIT_WINDOW;

  try {
    const currentCount = await redis.zcard(key);
    return {
      limit: RATE_LIMIT_MAX,
      remaining: Math.max(0, RATE_LIMIT_MAX - currentCount),
      resetTime: new Date(now + RATE_LIMIT_WINDOW),
    };
  } catch (error) {
    console.error("Rate limit status error:", error);
    return {
      limit: RATE_LIMIT_MAX,
      remaining: RATE_LIMIT_MAX,
      resetTime: new Date(now + RATE_LIMIT_WINDOW),
    };
  }
}
