import { NextRequest, NextResponse } from "next/server";
import { getAdminSession, getClientMetadata } from "@/lib/admin/auth";
import { db, verifyPassword, verifyPin } from "@/lib/admin/db";

export const dynamic = "force-dynamic";

// Rate limiting in-memory store for unlock attempts
const unlockAttempts = new Map<string, { count: number; lastAttempt: number }>();

/**
 * POST /api/admin/auth/unlock
 * Verifies the administrator's 4-digit PIN (or account password fallback) to dismiss the idle lock screen.
 * Restores workspace context without requiring a full re-login.
 */
export async function POST(req: NextRequest) {
  try {
    const ctx = await getAdminSession(req);
    if (!ctx) {
      return NextResponse.json(
        { error: "Session expired or invalid. Please sign in again." },
        { status: 401 }
      );
    }

    // Network Security check (Part 19: LOCK SCREEN + VPN)
    const { ip, userAgent, location } = getClientMetadata(req);
    const { getNetworkSecurity } = await import("@/lib/admin/network-security");
    const netSec = await getNetworkSecurity(ip || "127.0.0.1", req);
    if (netSec.isBlocked) {
      await db.updateSessionNetworkSecurity(ctx.session.tokenHash, netSec);
      await db.revokeSession(ctx.session.tokenHash, "SYSTEM", netSec.blockReason || "VPN detected during unlock");
      await db.createAuditLog({
        action: "NETWORK_SECURITY_BLOCKED",
        status: "FAILURE",
        userId: ctx.user.id,
        targetType: "SESSION",
        targetId: ctx.session.id,
        details: {
          reason: "Unlock blocked: Anonymized network connection detected",
          signals: {
            vpn: netSec.isVpn,
            proxy: netSec.isProxy,
            tor: netSec.isTor,
            relay: netSec.isRelay,
          },
          provider: netSec.provider,
          ip: netSec.ip,
          asn: netSec.asn,
        },
        location: ctx.session.location || location,
        networkSecurity: netSec,
        ipAddress: ip,
        userAgent,
      });

      return NextResponse.json(
        {
          code: "NETWORK_BLOCKED",
          error:
            "Admin access blocked: For security reasons, Quto AI does not allow administrator access through VPN, proxy, Tor, or anonymized network connections. Please disable your VPN/proxy and sign in again.",
          network: {
            isVpn: netSec.isVpn,
            isProxy: netSec.isProxy,
            isTor: netSec.isTor,
            isRelay: netSec.isRelay,
            reason: netSec.blockReason,
          },
        },
        { status: 403 }
      );
    }

    const body = await req.json().catch(() => ({}));
    const pin = typeof body.pin === "string" ? body.pin.trim() : "";
    const password = typeof body.password === "string" ? body.password : "";
    const credentialId =
      typeof body.credentialId === "string"
        ? body.credentialId
        : typeof body.webauthn?.id === "string"
        ? body.webauthn.id
        : "";

    if (!pin && !password && !credentialId) {
      return NextResponse.json(
        { error: "PIN, administrator password, or passkey is required to unlock." },
        { status: 400 }
      );
    }

    const user = await db.getUserById(ctx.user.id);
    if (!user || user.status !== "ACTIVE") {
      return NextResponse.json(
        { error: "Administrator account is inactive or disabled." },
        { status: 403 }
      );
    }

    // Rate limiting check on repeated unlock failures (5 attempts -> 60s lockout)
    const rateLimitKey = `unlock_${user.id}`;
    const recentFailures = unlockAttempts.get(rateLimitKey);
    const now = Date.now();
    if (recentFailures && recentFailures.count >= 5 && now - recentFailures.lastAttempt < 60000) {
      const waitSeconds = Math.ceil((60000 - (now - recentFailures.lastAttempt)) / 1000);
      return NextResponse.json(
        { error: `Too many failed attempts. Please wait ${waitSeconds} seconds before trying again.` },
        { status: 429 }
      );
    }

    let isValid = false;
    let method = "PIN";

    if (pin && user.pinHash && user.pinSalt) {
      isValid = verifyPin(pin, user.pinHash, user.pinSalt);
    } else if (password) {
      method = "PASSWORD";
      isValid = verifyPassword(password, user.passwordHash, user.passwordSalt);
    } else if (credentialId) {
      method = "PASSKEY";
      // Verify that this user owns the credential ID
      const matched = user.webauthnCredentials?.some((c) => c.id === credentialId);
      isValid = Boolean(matched);
    } else if (pin && !user.pinHash) {
      // User hasn't set a PIN yet, inform them to set PIN
      return NextResponse.json(
        { error: "Screen lock PIN not established. Please unlock with your password.", needsPinSetup: true },
        { status: 400 }
      );
    }

    if (!isValid) {
      const current = unlockAttempts.get(rateLimitKey) || { count: 0, lastAttempt: now };
      const newCount = current.count + 1;
      unlockAttempts.set(rateLimitKey, { count: newCount, lastAttempt: now });

      await db.logSecurityEvent({
        actorId: user.id,
        actorName: user.name,
        actorEmail: user.email,
        actorLevel: user.level,
        targetUserId: user.id,
        targetUserEmail: user.email,
        targetUserName: user.name,
        action: "PIN_FAILED",
        details: { method, attemptCount: newCount },
        ipAddress: ip,
      });

      const remaining = Math.max(0, 5 - newCount);
      const methodLabel = method === "PIN" ? "PIN" : method === "PASSWORD" ? "password" : "passkey credential";
      return NextResponse.json(
        {
          error:
            newCount >= 5
              ? "Too many failed attempts. Locked out for 60 seconds."
              : `Incorrect ${methodLabel}.${remaining > 0 ? ` ${remaining} attempt(s) remaining.` : ""}`,
        },
        { status: 401 }
      );
    }

    // Clear failed attempts on success
    unlockAttempts.delete(rateLimitKey);

    // Unlock session on the server
    await db.unlockSession(ctx.session.tokenHash);

    await db.logSecurityEvent({
      actorId: user.id,
      actorName: user.name,
      actorEmail: user.email,
      actorLevel: user.level,
      targetUserId: user.id,
      targetUserEmail: user.email,
      targetUserName: user.name,
      action: "SESSION_UNLOCKED",
      details: { method },
      ipAddress: ip,
    });

    return NextResponse.json({ success: true, isLocked: false, method });
  } catch (err: any) {
    console.error("[POST /api/admin/auth/unlock] Error:", err);
    return NextResponse.json(
      { error: err.message || "Failed to unlock session." },
      { status: 500 }
    );
  }
}
