import { getProfile } from "../../db/profile";
import { getPlanLimits, type Plan } from "../../utils/plan-features";
import { usePrisma } from "../../utils/prisma";

/**
 * GET /api/plan/change-preview?to=<free|pro|legend>
 *
 * Zeigt dem User vorab was sich bei einem Plan-Wechsel ändert.
 * Frontend baut den Briefing-Screen (§4, pricing-tiers.md) gegen diesen Endpoint.
 *
 * Response-Shape: siehe types unten.
 */

type ResourceKey =
  | "global_blocklist"
  | "custom_domains"
  | "mail_accounts"
  | "protected_devices"
  | "coach"
  | "tts"
  | "voice_picker"
  | "group_creation";

interface ChangeEntry {
  resource: ResourceKey;
  current: number | string;
  newLimit: number | string;
  overBy: number;
  action: "keep" | "limited" | "paused" | "grace_then_off" | "degraded" | "unlocked";
  detail: string;
  graceUntilDays?: number;
}

interface ChangePreviewResponse {
  from: Plan;
  to: Plan;
  direction: "upgrade" | "downgrade" | "same";
  gains: string[];
  keeps: string[];
  changes: ChangeEntry[];
}

const VALID_PLANS: Plan[] = ["free", "pro", "legend"];
const PLAN_ORDER: Record<Plan, number> = { free: 0, pro: 1, legend: 2 };

export default defineEventHandler(async (event): Promise<ChangePreviewResponse> => {
  const user = await requireUser(event);

  const query = getQuery(event);
  const toPlan = query.to as string | undefined;

  if (!toPlan || !VALID_PLANS.includes(toPlan as Plan)) {
    throw createError({
      statusCode: 400,
      data: {
        error: "INVALID_PLAN",
        message: `to must be one of: ${VALID_PLANS.join(", ")}`,
      },
    });
  }

  const profile = await getProfile(user.id);
  const rawPlan = profile?.plan ?? "free";
  const fromPlan = (rawPlan === "premium"
    ? "legend"
    : rawPlan === "standard"
      ? "pro"
      : rawPlan) as Plan;
  const to = toPlan as Plan;

  const isFoundingMember = profile?.foundingMember ?? false;

  const direction: "upgrade" | "downgrade" | "same" =
    PLAN_ORDER[to] > PLAN_ORDER[fromPlan]
      ? "upgrade"
      : PLAN_ORDER[to] < PLAN_ORDER[fromPlan]
        ? "downgrade"
        : "same";

  // Founding Member verliert nichts — leere changes
  if (isFoundingMember && direction === "downgrade") {
    return {
      from: fromPlan,
      to,
      direction: "same",
      gains: [],
      keeps: [
        "Dein Streak, deine Logs, dein Coach",
        "Dein bisheriger Schutz — alles bleibt",
        "Als Founding Member bleibt dein Plan dauerhaft erhalten",
      ],
      changes: [],
    };
  }

  const fromLimits = getPlanLimits(fromPlan);
  const toLimits = getPlanLimits(to);

  // ── Aktuelle Ressourcen-Counts laden ──────────────────────────────────────
  const db = usePrisma();

  const [
    activeMailCount,
    activeDomainCount,
    activeDeviceCount,
  ] = await Promise.all([
    db.mailConnection.count({ where: { userId: user.id, isActive: true, pausedAt: null } }),
    db.userCustomDomain.count({
      where: { userId: user.id, status: { notIn: ["approved", "rejected"] } },
    }),
    db.protectedDevice.count({
      where: { userId: user.id, status: { in: ["active", "pending"] } },
    }),
  ]);

  const changes: ChangeEntry[] = [];
  const gains: string[] = [];
  const keeps: string[] = [
    "Dein Streak, deine Logs, dein Coach — alles bleibt",
    "Nichts wird gelöscht. Alles Pausierte kommt sofort zurück wenn du wieder upgradest",
  ];

  // ── Global Blocklist ───────────────────────────────────────────────────────
  if (fromLimits.globalBlocklist !== toLimits.globalBlocklist) {
    if (direction === "downgrade") {
      // full → curated
      changes.push({
        resource: "global_blocklist",
        current: "volle Liste (~208.000 Domains)",
        newLimit: "kuratierte Kernliste (~1.000 Domains)",
        overBy: 0,
        action: "grace_then_off",
        detail:
          "Du hast noch 14 Tage Zugang zur vollen Blocklist. Danach sind deine " +
          "eigenen Domains weiter aktiv — trag jetzt deine wichtigsten ein.",
        graceUntilDays: 14,
      });
    } else {
      // curated → full
      gains.push("Volle Glücksspiel-Blocklist (~208.000 bekannte Domains)");
    }
  } else if (direction !== "same") {
    // Gleicher Wert — keine Änderung nötig, aber zum Kontext nennen
  }

  // ── Custom Domains ────────────────────────────────────────────────────────
  // Compare total (web + mail) to detect any bucket change
  const fromTotalDomains = fromLimits.customDomains.web + fromLimits.customDomains.mail;
  const toTotalDomains = toLimits.customDomains.web + toLimits.customDomains.mail;
  if (fromTotalDomains !== toTotalDomains) {
    if (direction === "downgrade") {
      const newLimitWeb = toLimits.customDomains.web;
      const newLimitMail = toLimits.customDomains.mail;
      const newLimitTotal = newLimitWeb + newLimitMail;
      const overBy = Math.max(0, activeDomainCount - newLimitTotal);
      changes.push({
        resource: "custom_domains",
        current: activeDomainCount,
        newLimit: newLimitTotal,
        overBy,
        action: "keep", // grandfathered — alle bleiben aktiv
        detail:
          overBy > 0
            ? `Du hast ${activeDomainCount} eigene Domains, ${to}-Plan erlaubt ${newLimitTotal} (${newLimitWeb} Web + ${newLimitMail} Mail). ` +
              `Alle bleiben aktiv — du kannst erst wieder welche hinzufügen wenn du unter dem jeweiligen Limit bist.`
            : `Du hast ${activeDomainCount} von ${newLimitTotal} möglichen Domains (${newLimitWeb} Web + ${newLimitMail} Mail) — kein Überlauf.`,
      });
    } else {
      const web = toLimits.customDomains.web;
      const mail = toLimits.customDomains.mail;
      gains.push(
        `Bis zu ${web} Web-Domains + ${mail} Mail-Patterns${toLimits.domainRefill ? " (Slots füllen sich auf wenn deine Domain in die globale Liste aufgenommen wird)" : ""}`,
      );
    }
  }

  // ── Domain Refill ─────────────────────────────────────────────────────────
  if (!fromLimits.domainRefill && toLimits.domainRefill && direction === "upgrade") {
    gains.push(
      "Domain-Slot-Refill: wenn ReBreak eine deiner eingereichten Domains genehmigt, wird der Slot frei",
    );
  }

  // ── Mail-Accounts ─────────────────────────────────────────────────────────
  const newMailLimit = toLimits.mailAgents;
  if (fromLimits.mailAgents !== newMailLimit) {
    if (direction === "downgrade" && newMailLimit !== Infinity) {
      const overBy = Math.max(0, activeMailCount - newMailLimit);
      if (overBy > 0) {
        changes.push({
          resource: "mail_accounts",
          current: activeMailCount,
          newLimit: newMailLimit,
          overBy,
          action: "paused",
          detail:
            `Du hast ${activeMailCount} verbundene Postfächer, ${to}-Plan schützt ${newMailLimit}. ` +
            `Die ${overBy} zuletzt hinzugefügten werden pausiert — nicht gelöscht. ` +
            "Ein letzter Scan läuft noch durch bevor sie pausiert werden. " +
            "Bei Re-Upgrade kommen sie sofort zurück.",
        });
      } else {
        changes.push({
          resource: "mail_accounts",
          current: activeMailCount,
          newLimit: newMailLimit,
          overBy: 0,
          action: "keep",
          detail: `Du hast ${activeMailCount} von ${newMailLimit} möglichen Postfächern — kein Überlauf.`,
        });
      }
    } else if (direction === "upgrade") {
      const limitText = newMailLimit === Infinity ? "unbegrenzt" : String(newMailLimit);
      gains.push(
        newMailLimit === Infinity
          ? "Unbegrenzt viele Mail-Postfächer schützen (Echtzeit-Scan geplant)"
          : `Bis zu ${limitText} Mail-Postfächer`,
      );
    }
  }

  // ── Protected Devices (Mac/Windows DNS-Profile) ───────────────────────────
  if (fromLimits.maxProtectedDevices !== toLimits.maxProtectedDevices) {
    if (direction === "downgrade" && toLimits.maxProtectedDevices === 0) {
      const overBy = activeDeviceCount;
      if (overBy > 0) {
        changes.push({
          resource: "protected_devices",
          current: activeDeviceCount,
          newLimit: 0,
          overBy,
          action: "degraded",
          detail:
            `Du hast ${activeDeviceCount} geschützte(s) Gerät(e). Diese laufen noch 14 Tage auf voller ` +
            "Blocklist weiter. Danach liefert der DNS-Filter für diese Geräte keinen Schutz mehr — " +
            "das Profil bleibt auf dem Gerät (entferne es manuell unter System-Einstellungen). " +
            "Bei Re-Upgrade auf Legend: sofort wieder voll aktiv.",
          graceUntilDays: 14,
        });
      }
    } else if (direction === "upgrade") {
      gains.push(
        `Bis zu ${toLimits.maxProtectedDevices} weitere Geräte (Mac/Windows) per DNS-Profil schützen`,
      );
    }
  }

  // ── Coach ─────────────────────────────────────────────────────────────────
  if (fromLimits.aiModel !== toLimits.aiModel) {
    if (direction === "downgrade") {
      changes.push({
        resource: "coach",
        current: friendlyModelName(fromLimits.aiModel),
        newLimit: friendlyModelName(toLimits.aiModel),
        overBy: 0,
        action: "limited",
        detail:
          "Dein Coach läuft ab jetzt auf einem anderen Modell — er ist weiter da, immer.",
      });
    } else {
      gains.push(`Lyra läuft auf ${friendlyModelName(toLimits.aiModel)} — feinfühligere Gespräche`);
    }
  }

  // ── TTS ───────────────────────────────────────────────────────────────────
  if (
    fromLimits.voice.provider !== toLimits.voice.provider ||
    fromLimits.voice.dailyQuotaSeconds !== toLimits.voice.dailyQuotaSeconds
  ) {
    if (direction === "downgrade") {
      const fromQuota =
        fromLimits.voice.dailyQuotaSeconds === 0
          ? "unbegrenzt"
          : `${fromLimits.voice.dailyQuotaSeconds / 60} Min/Tag`;
      const toQuota =
        toLimits.voice.dailyQuotaSeconds === 0
          ? "unbegrenzt"
          : `${toLimits.voice.dailyQuotaSeconds / 60} Min/Tag`;
      changes.push({
        resource: "tts",
        current: `${friendlyProviderName(fromLimits.voice.provider)}, ${fromQuota}`,
        newLimit: `${friendlyProviderName(toLimits.voice.provider)}, ${toQuota}`,
        overBy: 0,
        action: "limited",
        detail:
          `Sprachausgabe wechselt auf ${friendlyProviderName(toLimits.voice.provider)} (${toQuota}). ` +
          "Deine gewählte Stimme merken wir uns — bei Re-Upgrade sofort wieder aktiv.",
      });
    } else {
      const toQuota =
        toLimits.voice.dailyQuotaSeconds === 0
          ? "unbegrenzt"
          : `${toLimits.voice.dailyQuotaSeconds / 60} Min/Tag`;
      gains.push(
        `${friendlyProviderName(toLimits.voice.provider)} Sprachausgabe (${toQuota})`,
      );
    }
  }

  // ── Voice Picker (Legend-only) ────────────────────────────────────────────
  if (fromPlan === "legend" && to !== "legend" && direction === "downgrade") {
    changes.push({
      resource: "voice_picker",
      current: "Stimme wählbar",
      newLimit: "Standard-Stimme",
      overBy: 0,
      action: "limited",
      detail:
        "Die Lyra-Stimme wird auf Standard zurückgesetzt. Deine Auswahl bleibt gespeichert — " +
        "bei Re-Upgrade sofort wieder aktiv.",
    });
  } else if (to === "legend" && fromPlan !== "legend" && direction === "upgrade") {
    gains.push("Lyra-Stimme frei wählbar");
  }

  // ── Group Creation (Legend-only) ──────────────────────────────────────────
  if (fromLimits.canCreateGroup && !toLimits.canCreateGroup && direction === "downgrade") {
    changes.push({
      resource: "group_creation",
      current: "Gruppen gründen erlaubt",
      newLimit: "Keine neuen Gruppen",
      overBy: 0,
      action: "keep", // bestehende Gruppen bleiben (grandfathered)
      detail:
        "Bestehende Gruppen bleiben — du bleibst Admin. " +
        "Neue Gruppen gründen geht erst wieder ab Legend.",
    });
  } else if (!fromLimits.canCreateGroup && toLimits.canCreateGroup && direction === "upgrade") {
    gains.push("Eigene Community-Gruppen gründen");
  }

  // ── Same-Plan: alles leer ─────────────────────────────────────────────────
  if (direction === "same") {
    return {
      from: fromPlan,
      to,
      direction: "same",
      gains: [],
      keeps,
      changes: [],
    };
  }

  return {
    from: fromPlan,
    to,
    direction,
    gains,
    keeps,
    changes,
  };
});

function friendlyModelName(model: string): string {
  if (model.includes("claude-3.5-haiku") || model.includes("claude-3-haiku")) return "Claude (Haiku)";
  if (model.includes("llama-3.3-70b")) return "Llama 70B";
  if (model.includes("llama-3.1-8b")) return "Llama 8B";
  return model;
}

function friendlyProviderName(provider: string): string {
  const map: Record<string, string> = {
    elevenlabs: "ElevenLabs",
    cartesia: "Cartesia",
    google: "Google",
    openai: "OpenAI",
    azure: "Azure",
  };
  return map[provider] ?? provider;
}
