import { usePrisma } from "../utils/prisma";

export interface ProtectedDeviceRecord {
  id: string;
  platform: string;
  label: string;
  status: string;
  installedAt: Date | null;
  degradedAt: Date | null;
  createdAt: Date;
}

export interface ProtectedDeviceWithToken extends ProtectedDeviceRecord {
  dnsToken: string;
  userId: string;
}

const DEVICE_SELECT = {
  id: true,
  platform: true,
  label: true,
  status: true,
  installedAt: true,
  degradedAt: true,
  createdAt: true,
} as const;

const DEVICE_SELECT_WITH_TOKEN = {
  ...DEVICE_SELECT,
  dnsToken: true,
  userId: true,
} as const;

/** Alle nicht-revoked Devices eines Users, neueste zuerst. */
export async function listProtectedDevices(
  userId: string,
): Promise<ProtectedDeviceRecord[]> {
  const db = usePrisma();
  return db.protectedDevice.findMany({
    where: { userId, status: { not: "revoked" } },
    orderBy: { createdAt: "desc" },
    select: DEVICE_SELECT,
  });
}

/** Anzahl der aktiven+pending Devices für Limit-Check (degraded zählt NICHT — Slot freigegeben). */
export async function countActiveProtectedDevices(
  userId: string,
): Promise<number> {
  const db = usePrisma();
  return db.protectedDevice.count({
    where: { userId, status: { in: ["active", "pending"] } },
  });
}

/** Lookup by id — inkl. dnsToken und userId (für mobileconfig-Generation + ownership-check). */
export async function getProtectedDevice(
  id: string,
): Promise<ProtectedDeviceWithToken | null> {
  const db = usePrisma();
  return db.protectedDevice.findUnique({
    where: { id },
    select: DEVICE_SELECT_WITH_TOKEN,
  });
}

/** Lookup by dnsToken — für DoH-Blocklist-Endpoint (Token aus URL). */
export async function getProtectedDeviceByToken(
  dnsToken: string,
): Promise<ProtectedDeviceWithToken | null> {
  const db = usePrisma();
  return db.protectedDevice.findUnique({
    where: { dnsToken },
    select: DEVICE_SELECT_WITH_TOKEN,
  });
}

/** Anlegen eines neuen ProtectedDevice (status=pending). */
export async function createProtectedDevice(opts: {
  userId: string;
  dnsToken: string;
  platform: string;
  label: string;
}): Promise<ProtectedDeviceWithToken> {
  const db = usePrisma();
  return db.protectedDevice.create({
    data: {
      userId: opts.userId,
      dnsToken: opts.dnsToken,
      platform: opts.platform,
      label: opts.label,
      status: "pending",
    },
    select: DEVICE_SELECT_WITH_TOKEN,
  });
}

/** User bestätigt Installation — setzt installedAt + status=active. */
export async function confirmProtectedDeviceInstalled(
  id: string,
  userId: string,
): Promise<ProtectedDeviceRecord | null> {
  const db = usePrisma();
  const device = await db.protectedDevice.findFirst({
    where: { id, userId, status: { not: "revoked" } },
  });
  if (!device) return null;

  return db.protectedDevice.update({
    where: { id },
    data: {
      status: "active",
      installedAt: new Date(),
    },
    select: DEVICE_SELECT,
  });
}

/** Soft-delete: setzt status=revoked + revokedAt. Ownership-check via userId. */
export async function revokeProtectedDevice(
  id: string,
  userId: string,
): Promise<boolean> {
  const db = usePrisma();
  const device = await db.protectedDevice.findFirst({
    where: { id, userId, status: { not: "revoked" } },
  });
  if (!device) return false;

  await db.protectedDevice.update({
    where: { id },
    data: { status: "revoked", revokedAt: new Date() },
  });
  return true;
}

/**
 * DoH-Handshake: lookup by dnsToken, flip pending→active, always update lastDnsQueryAt.
 *
 * Returns:
 *   { found: false }                         → Token unbekannt
 *   { found: true, statusChanged: false, ... } → war schon active/degraded, nur lastDnsQueryAt updated
 *   { found: true, statusChanged: true, ... }  → war pending, jetzt active
 *   { found: true, revoked: true }             → Token existiert aber revoked → ignorieren
 */
export async function handshakeProtectedDevice(dnsToken: string): Promise<
  | { found: false }
  | { found: true; revoked: true }
  | { found: true; revoked: false; statusChanged: boolean; status: string }
> {
  const db = usePrisma();
  const device = await db.protectedDevice.findUnique({ where: { dnsToken } });
  if (!device) return { found: false };
  if (device.status === "revoked") return { found: true, revoked: true };

  const now = new Date();
  const updateData: Record<string, unknown> = { lastDnsQueryAt: now };
  const wasPending = device.status === "pending";
  if (wasPending) {
    updateData.status = "active";
    updateData.installedAt = now;
  }

  await db.protectedDevice.update({ where: { id: device.id }, data: updateData });
  return { found: true, revoked: false, statusChanged: wasPending, status: wasPending ? "active" : device.status };
}

/**
 * Prüft ob ein Token nach der 14-Tage-Grace-Period in Passthrough-Modus ist.
 * Wird vom DoH-Blocklist-Endpoint aufgerufen.
 *
 * Returns:
 *   'active'    → volle Blocklist liefern
 *   'grace'     → volle Blocklist liefern (innerhalb 14-Tage-Grace)
 *   'passthrough' → nur minimale/leere Liste liefern
 *   'revoked'   → Token unbekannt oder revoked → Passthrough
 */
export async function getDeviceBlocklistMode(
  dnsToken: string,
): Promise<"active" | "grace" | "passthrough" | "revoked"> {
  const device = await getProtectedDeviceByToken(dnsToken);
  if (!device) return "revoked";
  if (device.status === "revoked") return "revoked";
  if (device.status === "active" || device.status === "pending") return "active";
  if (device.status === "degraded") {
    const GRACE_MS = 14 * 24 * 60 * 60 * 1000;
    const gracedAt = device.degradedAt
      ? device.degradedAt.getTime() + GRACE_MS
      : 0;
    if (Date.now() <= gracedAt) return "grace";
    return "passthrough";
  }
  return "passthrough";
}
