import { getProfile } from "../../db/profile";
import {
  findActiveDeviceLock,
  bindDeviceToUser,
  isLockingPlan,
  markDeviceLockNotified,
} from "../../db/devices";
import {
  isLockNotifyRateLimited,
  sendDeviceLockEmail,
} from "../../utils/device-lock-email";

/**
 * POST /api/devices/check-lock
 *
 * Authenticated Device-Account-Lock-Check für Native-Auth-Flow.
 *
 * Die native App nutzt supabase.auth.signInWithPassword direkt (BFF-Pattern
 * gilt für token-storage, nicht für den Auth-Call selbst). Nach dem Sign-In
 * ruft der Auth-Store diesen Endpoint mit dem frischen JWT auf.
 *
 * Warum separater Endpoint statt /api/auth/login:
 *   - /api/auth/login ist für username+password (BFF-Signin mit internal-email-trick)
 *   - Native-Auth geht direkt via Supabase-SDK → JWT vorhanden, kein Password-Re-Entry
 *   - Dieser Endpoint prüft POST-AUTH ob das Device an einen anderen Account gebunden ist
 *
 * Auth: requireUser mit skipDeviceCheck=true — kein Chicken-Egg-Problem.
 *   - skipDeviceCheck=true: verhindert dass requireUser selbst einen 403 wirft
 *     wenn das Device noch nicht registriert ist (Lock-Check muss VOR Register laufen)
 *
 * Request Headers:
 *   - Authorization: Bearer <access_token>
 *   - x-device-id: <persistent device UUID>
 *
 * Response:
 *   - 200: { ok: true } — kein Lock, Device ggf. an currentUser gebunden (Pro/Legend)
 *   - 400: { error: "DEVICE_ID_REQUIRED" } — x-device-id Header fehlt
 *   - 409: { error: "DEVICE_LOCKED", lockedUntil, releaseRequestable }
 *
 * Side-effects bei 200 (Pro/Legend only):
 *   - bindDeviceToUser — idempotent, nur wenn noch nicht gebunden
 *
 * Side-effects bei 409:
 *   - sendDeviceLockEmail — Rate-Limited auf 1 Mail / 6h via lockNotifiedAt
 *   - markDeviceLockNotified — schreibt lockNotifiedAt in DB
 */
export default defineEventHandler(async (event) => {
  // skipDeviceCheck=true: requireUser darf nicht selbst Device-Logic auslösen —
  // dieser Endpoint IST der Device-Check. Ohne diesen Flag: 403-Loop möglich wenn
  // Device noch nicht in UserDevice-Table (Erstlogin vor register-Endpoint).
  const user = await requireUser(event, { skipDeviceCheck: true });

  const deviceId = getHeader(event, "x-device-id");

  if (!deviceId) {
    throw createError({
      statusCode: 400,
      data: { error: "DEVICE_ID_REQUIRED" },
    });
  }

  // ─── Lock-Check ───────────────────────────────────────────────────────────
  // findActiveDeviceLock matched: deviceId + NOT userId=currentUser.
  // Wenn kein Lock für einen anderen User → null → weiter.
  const lock = await findActiveDeviceLock(deviceId, user.id);

  if (lock) {
    // ─── Mail-Notification an Original-User (Rate-Limited 6h) ─────────────
    if (!isLockNotifyRateLimited(lock.lockNotifiedAt)) {
      const config = useRuntimeConfig(event);
      const supabaseCfg = (config as any).public?.supabase ?? (config as any).supabase;
      const resendApiKey = (config as any).resendApiKey as string | undefined;
      const supabaseServiceKey = (config as any).supabaseServiceKey as string | undefined;

      // Fire-and-forget — 409 wird sofort geworfen, Mail läuft async
      void (async () => {
        try {
          const ownerProfile = await getProfile(lock.userId);
          if (ownerProfile && resendApiKey && supabaseServiceKey) {
            const { createClient } = await import("@supabase/supabase-js");
            const adminClient = createClient(
              supabaseCfg.url as string,
              supabaseServiceKey,
            );
            const { data: adminUser } = await adminClient.auth.admin.getUserById(lock.userId);
            const ownerEmail = adminUser?.user?.email;

            if (ownerEmail) {
              await sendDeviceLockEmail({
                recipientNickname: ownerProfile.nickname ?? ownerProfile.username ?? "Nutzer",
                recipientEmail: ownerEmail,
                deviceRowId: lock.id,
                deviceName: lock.name,
                lockNotifiedAt: lock.lockNotifiedAt,
                resendApiKey,
              });
              await markDeviceLockNotified(lock.id);
            }
          }
        } catch (mailErr: any) {
          console.error("[check-lock] device-lock mail failed:", mailErr?.message ?? mailErr);
        }
      })();
    }

    // lockedUntil: releaseRequestedAt + 24h, oder null wenn kein Release beantragt
    const lockedUntil = lock.releaseRequestedAt
      ? new Date(lock.releaseRequestedAt.getTime() + 24 * 60 * 60 * 1000).toISOString()
      : null;

    throw createError({
      statusCode: 409,
      statusMessage: "DEVICE_LOCKED",
      data: {
        error: "DEVICE_LOCKED",
        lockedUntil,
        releaseRequestable: true,
      },
    });
  }

  // ─── Kein Lock — ggf. Device an currentUser binden ───────────────────────
  // Pro/Legend-User: idempotentes Binding (boundToPlan=null → setzen).
  // Free-User: kein Binding (isLockingPlan-Guard in bindDeviceToUser).
  // Fire-and-forget — 200 soll nicht durch Binding-Fehler blockiert werden.
  const profile = await getProfile(user.id);
  const plan = profile?.plan ?? "free";

  if (isLockingPlan(plan)) {
    void bindDeviceToUser(user.id, deviceId, plan).catch((err: any) => {
      console.error("[check-lock] device-bind failed:", err?.message ?? err);
    });
  }

  return { ok: true };
});
