import {
  IP_BAN_TTL_SECONDS,
  IP_RATE_LIMIT,
  IP_RATE_WINDOW_SECONDS,
} from "@/lib/constants/cache";
import { withBoundedRedis } from "@/lib/redis";
import { writeAlert } from "@/modules/alert/service";

export type IpRateLimitResult =
  | { allowed: true }
  | { allowed: false; errorCode: "RATE_LIMITED"; banned: boolean };

function ipRateKey(ip: string): string {
  return `ratelimit:ip:${ip}`;
}

function ipBanKey(ip: string): string {
  return `ban:ip:${ip}`;
}

/** IP 级限流：1000 次/分钟，超限封禁 10 分钟 */
export async function checkIpRateLimit(
  ip: string,
): Promise<IpRateLimitResult> {
  const result = await withBoundedRedis(async (redis) => {
    const banned = await redis.exists(ipBanKey(ip));
    if (banned === 1) {
      return { allowed: false as const, errorCode: "RATE_LIMITED" as const, banned: true };
    }

    const key = ipRateKey(ip);
    const count = await redis.incr(key);

    if (count === 1) {
      await redis.expire(key, IP_RATE_WINDOW_SECONDS);
    }

    if (count > IP_RATE_LIMIT) {
      await redis.set(ipBanKey(ip), "1", "EX", IP_BAN_TTL_SECONDS);
      void writeAlert("SECURITY", {
        detail: {
          reason: "ip_rate_limit_ban",
          ip,
          count,
          window_seconds: IP_RATE_WINDOW_SECONDS,
        },
      });
      return { allowed: false as const, errorCode: "RATE_LIMITED" as const, banned: true };
    }

    return { allowed: true as const };
  });

  if (!result) {
    return { allowed: true };
  }
  return result;
}
