import { NextRequest, NextResponse } from "next/server";
import { eq } from "drizzle-orm";
import { db, isDatabaseAvailable, schema } from "@/lib/db";
import { MAX_JSON_BODY_BYTES } from "@/lib/limits";
import { readJsonSized } from "@/lib/http/requestSize";
import { requireCsrf } from "@/lib/auth/csrf";
import { clientIp, rateLimit } from "@/lib/security/rateLimit";

export const runtime = "nodejs";

/**
 * Public, unauthenticated endpoint (documented in STRIPE_SETUP_GUIDE.md as a
 * plain `curl` lookup by license key or Stripe session id) — so it cannot
 * require a session, but it must not be a free enumeration/brute-force oracle
 * over license keys. One shared IP budget covers GET and POST since both hit
 * the same underlying lookup.
 */
function rateLimitedResponse(retryAfter: number) {
  return NextResponse.json(
    { valid: false, plan: null, status: "rate_limited", expiresAt: null, error: "Zu viele Anfragen." },
    { status: 429, headers: { "Retry-After": String(retryAfter) } }
  );
}

function checkLicenseVerifyRateLimit(req: NextRequest): NextResponse | null {
  const ip = clientIp(req);
  const burst = rateLimit(`license_verify:burst:ip:${ip}`, 20, 10 * 60 * 1000);
  if (!burst.allowed) return rateLimitedResponse(burst.retryAfter);
  const hourly = rateLimit(`license_verify:ip:${ip}`, 60, 60 * 60 * 1000);
  if (!hourly.allowed) return rateLimitedResponse(hourly.retryAfter);
  return null;
}

interface VerificationResult {
  valid: boolean;
  plan: string | null;
  status: string;
  expiresAt: string | null;
  licenseKey?: string;
  source: "database";
  error?: string;
}

async function verifyCredentials(
  licenseKey?: string | null,
  sessionId?: string | null
): Promise<VerificationResult> {
  const normalizedKey = licenseKey ? licenseKey.trim() : null;
  const normalizedSessionId = sessionId ? sessionId.trim() : null;

  if (!normalizedKey && !normalizedSessionId) {
    return {
      valid: false,
      plan: null,
      status: "missing_credentials",
      expiresAt: null,
      source: "database",
      error: "Entweder licenseKey oder sessionId muss angegeben werden.",
    };
  }

  let hasDb = false;
  try {
    hasDb = await isDatabaseAvailable();
  } catch {
    hasDb = false;
  }

  if (!hasDb) {
    return {
      valid: false,
      plan: null,
      status: "service_unavailable",
      expiresAt: null,
      source: "database",
      error: "Datenbank nicht verfügbar.",
    };
  }

  try {
    let records: (typeof schema.licenses.$inferSelect)[] = [];

    if (normalizedKey) {
      records = await db
        .select()
        .from(schema.licenses)
        .where(eq(schema.licenses.licenseKey, normalizedKey))
        .limit(1);
    } else if (normalizedSessionId) {
      records = await db
        .select()
        .from(schema.licenses)
        .where(eq(schema.licenses.stripeCheckoutSessionId, normalizedSessionId))
        .limit(1);
    }

    if (records && records.length > 0) {
      const license = records[0];
      const now = new Date();
      const isExpired = license.expiresAt ? new Date(license.expiresAt) < now : false;
      const isValid = license.status === "active" && !isExpired;

      return {
        valid: isValid,
        plan: license.plan,
        status: isExpired ? "expired" : license.status,
        expiresAt: license.expiresAt ? license.expiresAt.toISOString() : null,
        licenseKey: license.licenseKey,
        source: "database",
      };
    }

    // Record not found in database
    return {
      valid: false,
      plan: null,
      status: "not_found",
      expiresAt: null,
      source: "database",
    };
  } catch (dbErr) {
    console.error("Database verification failed:", dbErr);
    return {
      valid: false,
      plan: null,
      status: "database_error",
      expiresAt: null,
      source: "database",
      error: "Datenbankfehler während der Lizenzprüfung.",
    };
  }
}

export async function GET(req: NextRequest) {
  try {
    const limited = checkLicenseVerifyRateLimit(req);
    if (limited) return limited;

    const { searchParams } = new URL(req.url);
    const licenseKey = searchParams.get("key") || searchParams.get("licenseKey");
    const sessionId = searchParams.get("sessionId") || searchParams.get("session_id");

    const result = await verifyCredentials(licenseKey, sessionId);
    if (result.status === "service_unavailable" || result.status === "database_error") {
      return NextResponse.json(result, { status: 503 });
    }
    return NextResponse.json(result, { status: 200 });
  } catch (error: any) {
    console.error("License Verify GET Error:", error);
    return NextResponse.json(
      { valid: false, plan: null, status: "error", error: error?.message || "Internal server error" },
      { status: 500 }
    );
  }
}

export async function POST(req: NextRequest) {
  try {
    const csrfBlocked = requireCsrf(req);
    if (csrfBlocked) return csrfBlocked;

    const limited = checkLicenseVerifyRateLimit(req);
    if (limited) return limited;

    const parsed = await readJsonSized<{
      licenseKey?: string;
      key?: string;
      sessionId?: string;
      session_id?: string;
    }>(req, MAX_JSON_BODY_BYTES);
    if (!parsed.ok) return parsed.response;
    const body = parsed.body ?? {};
    const licenseKey = body.licenseKey || body.key;
    const sessionId = body.sessionId || body.session_id;

    const result = await verifyCredentials(licenseKey, sessionId);
    if (result.status === "service_unavailable" || result.status === "database_error") {
      return NextResponse.json(result, { status: 503 });
    }
    return NextResponse.json(result, { status: 200 });
  } catch (error: any) {
    console.error("License Verify POST Error:", error);
    return NextResponse.json(
      { valid: false, plan: null, status: "error", error: error?.message || "Internal server error" },
      { status: 500 }
    );
  }
}