"use client";

import { useEffect, useState } from "react";
import "klaro/dist/klaro.css";
import type { TrackingCode } from "../lib/payload";
import { buildKlaroConfig } from "../lib/klaroConfig";
import { loadTrackingCode } from "../lib/loadTrackingCode";

// Replaced a hand-rolled CookieBanner.tsx + useConsent.ts + TrackingScripts.tsx
// with kiprotect/klaro (open source, self-hosted, npm install klaro) —
// the custom banner only ever covered the accept/reject UI itself; Klaro
// additionally brings a real per-service consent list, bundled German UI
// translations, and (via `cookies`, not used here yet) cookie-deletion on
// withdrawal — all things a hand-rolled version would have had to build
// from scratch. See project memory for the fuller reasoning.
//
// Dynamically imported inside an effect (client-only, after mount) rather
// than a static top-level import — Klaro touches `window`/`document` at
// module-eval time in places, which isn't SSR-safe. The CSS import above
// stays static (Next.js requires CSS imports to be static, not inside a
// dynamic import()), paired with the "-no-css" JS build so the stylesheet
// isn't loaded twice.
//
// `buildKlaroConfig`'s `styling` CSS-var overrides (brand colors, corner
// position) only get Klaro so far — its bundled klaro.css still draws its
// own border/shadow/spacing/typography, which read as an obviously
// bolted-on library widget next to this site's own hand-designed
// components (NewsletterModal.tsx, NotifyMeForm.tsx, etc.). The <style>
// block below is a real CSS override pass against Klaro's actual DOM
// classnames (confirmed against kiprotect/klaro's own src/scss/*.scss,
// not guessed) — same "plain unlayered <style> tag wins the cascade"
// approach the Payload admin's own AdminUIStyles.tsx uses, `!important`
// added only where needed to beat klaro.css's own rules of otherwise-equal
// specificity. Kills Klaro's default border entirely (replaced with a
// soft shadow, matching this site's own card language) and restyles
// every button to the site's actual rounded/weighted look instead of
// Klaro's generic flat rectangles.
function KlaroTheme() {
  return (
    <style>{`
      /* Blanket reset first — the previous pass only targeted
         .cookie-notice/.cookie-modal directly and a hard black border
         still showed up in production (screenshot-confirmed), so every
         descendant gets border/outline stripped here regardless of which
         specific Klaro rule was actually drawing it; the two rules below
         re-add exactly the borders this theme actually wants. */
      .klaro, .klaro * { box-sizing: border-box; border: 0 !important; outline: 0 !important; }
      .klaro .cookie-notice, .klaro .cookie-modal {
        box-shadow: 0 20px 44px -14px rgba(26,26,24,0.22), 0 4px 14px rgba(26,26,24,0.07) !important;
        border-radius: 18px !important;
        font-family: var(--font-inter), -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
      }
      .klaro .cookie-notice .cn-body { padding: 22px 24px !important; }
      .klaro .cookie-notice p, .klaro .cookie-modal p {
        font-size: 14px !important;
        line-height: 1.6 !important;
        margin-top: 0 !important;
        margin-bottom: 10px !important;
      }
      .klaro h1, .klaro h2 {
        font-family: var(--font-lora), Georgia, serif !important;
        font-weight: 700 !important;
        letter-spacing: -0.01em !important;
      }
      .klaro .cm-btn {
        border: none !important;
        border-radius: 8px !important;
        font-weight: 700 !important;
        font-size: 13px !important;
        padding: 10px 18px !important;
        transition: opacity 0.15s ease, transform 0.15s ease;
      }
      .klaro .cm-btn:hover { opacity: 0.88; }
      .klaro .cm-btn:active { transform: scale(0.97); }
      .klaro .cm-btn:focus-visible { outline: 2px solid #f6a701 !important; outline-offset: 2px; }
      /* Side-by-side by default (accept/decline in the notice, the
         modal's own bottom action row), only wrapping to a stacked
         layout once they genuinely don't fit — flex-wrap does this
         naturally at any width, no fixed breakpoint needed. Klaro's own
         .cn-ok/.cn-buttons rely on inline-block flow for the same
         result, which is fragile; this is the explicit version. */
      .klaro .cn-ok, .klaro .cn-buttons, .klaro .cm-buttons {
        display: flex !important;
        flex-wrap: wrap !important;
        gap: 10px !important;
        width: auto !important;
      }
      .klaro .cn-buttons .cm-btn, .klaro .cm-buttons .cm-btn { width: auto !important; margin: 0 !important; }
      /* The "Karte laden?" placeholder ContextualConsentNotice renders in
         place of a gated embed (GoogleMapsEmbed.tsx) — fills that embed's
         own aspect-ratio box, so this needs to look like a real card
         slot, not a bare unstyled div floating inside it. */
      .klaro.cm-as-context-notice {
        height: 100% !important;
        display: flex !important;
        align-items: center !important;
        justify-content: center !important;
      }
      .klaro .context-notice {
        width: 100% !important;
        height: 100% !important;
        display: flex !important;
        flex-direction: column !important;
        align-items: center !important;
        justify-content: center !important;
        gap: 4px !important;
        padding: 24px !important;
        background: #fffdf8 !important;
        text-align: center !important;
      }
      .klaro .context-notice p { text-align: center !important; max-width: 32ch; }
      .klaro .context-notice .cm-buttons { display: flex !important; gap: 10px !important; margin-top: 6px !important; }
      .klaro a.cm-link, .klaro .cookie-notice a, .klaro .cookie-modal a {
        color: #a06b00 !important;
        text-decoration: underline !important;
        font-weight: 600 !important;
      }
      .klaro select, .klaro .cm-list-input + label {
        border-radius: 6px !important;
      }

      /* ---- Settings modal service/purpose list — a real pass modeled on
         well-known CMPs like Cookiebot (roomier modal, clear row
         separators, bigger switches, muted-but-legible descriptions),
         not just inherited from the notice's own styling. Class names
         confirmed against node_modules/klaro's src/scss/switch.scss +
         klaro.scss, not guessed. */
      /* Explicit centering on both axes, not Klaro's own margin:auto —
         that only applies above Klaro's internal (JS-set, not a CSS var
         this theme controls) centerWidth breakpoint; below it the modal
         is position:fixed/width:100% with no left/margin at all, so an
         unconditional max-width override (needed for the wider 640px
         modal below) left it flush against the left edge instead of
         centered — confirmed via screenshot 2026-08-02. left:50% +
         translate(-50%,-50%) centers correctly at every viewport size
         regardless of which of Klaro's own breakpoint branches is active. */
      .klaro .cookie-modal {
        position: fixed !important;
        left: 50% !important;
        top: 50% !important;
        transform: translate(-50%, -50%) !important;
        width: calc(100% - 40px) !important;
        max-width: 640px !important;
        margin: 0 !important;
      }
      .klaro .cookie-modal .cn-body { padding: 32px 36px !important; }
      .klaro .cookie-modal h1 { font-size: 26px !important; margin-bottom: 4px !important; }
      .klaro .cookie-modal > .cn-body > p:first-of-type { color: #6b6b69 !important; margin-bottom: 24px !important; }

      /* Re-adds a deliberate row separator the blanket border-reset above
         removes — each purpose/service row genuinely benefits from one,
         unlike the notice's own outer border which just looked heavy. */
      .klaro .cm-switch-container {
        border-bottom: 1px solid #e5e0d8 !important;
        padding: 16px 4px !important;
        padding-left: 70px !important;
      }
      .klaro .cm-switch-container:last-child { border-bottom: 0 !important; }
      .klaro .cm-list-title { font-size: 15px !important; font-weight: 700 !important; }
      .klaro .cm-list-description { font-size: 13.5px !important; line-height: 1.5 !important; padding-top: 5px !important; max-width: 46ch; }
      .klaro p.purposes { font-size: 12px !important; font-weight: 600 !important; text-transform: uppercase; letter-spacing: 0.04em; margin-top: 6px !important; }

      /* Bigger, clearer toggle (44×24 vs. Klaro's cramped 50×30-but-
         visually-thin default) — brand amber when on, plain border-tone
         off, matching this site's own bg-brand/bg-border pairing. */
      .klaro .cm-switch, .klaro .cm-list-input { width: 44px !important; height: 24px !important; }
      .klaro .slider { border: 1px solid #e5e0d8 !important; }
      .klaro .slider::before { width: 18px !important; height: 18px !important; left: 3px !important; bottom: 2px !important; box-shadow: 0 1px 2px rgba(0,0,0,0.15) !important; }
      .klaro .cm-list-input:checked + .cm-list-label .slider::before { transform: translateX(19px) !important; }

      .klaro .cm-caret { color: #6b6b69 !important; }

      /* Bottom action row reads as a distinct footer, not just the last
         list item — separated + slightly recessed. */
      .klaro .cookie-modal .cm-buttons {
        border-top: 1px solid #e5e0d8 !important;
        margin-top: 24px !important;
        padding-top: 20px !important;
      }

      /* Hides the "alle umschalten" toggle's own boilerplate description
         ("Mit diesem Schalter können Sie alle Dienste aktivieren oder
         deaktivieren.") — redundant next to a plainly-labeled switch.
         CSS hide, not an empty translation override — Klaro's own t()
         treats an empty string as "translation missing" and renders a
         literal "[missing translation: ...]" debug string instead
         (confirmed via screenshot 2026-08-02), which is worse than the
         original text. */
      .klaro .cm-toggle-all .cm-list-description { display: none !important; }
    `}</style>
  );
}

export function KlaroConsentManager({ codes }: { codes: TrackingCode[] }) {
  // Kept in state (not just called once) so the persistent reopen button
  // below can call Klaro.show() itself, any time after the initial
  // accept/reject decision — a visitor must always be able to revisit
  // their choice, not just on first load.
  const [klaroModule, setKlaroModule] = useState<typeof import("klaro/dist/klaro-no-css") | null>(null);

  useEffect(() => {
    // Nothing to ask consent for — don't even load/render Klaro. A cookie
    // banner with zero services to list would just be visual noise.
    if (codes.length === 0) return;

    let cancelled = false;
    import("klaro/dist/klaro-no-css").then((Klaro) => {
      if (cancelled) return;
      const config = buildKlaroConfig(codes, loadTrackingCode);
      Klaro.setup(config);
      setKlaroModule(Klaro);
    });
    return () => {
      cancelled = true;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps -- `codes` comes
    // from a server-fetched, 60s-ISR-cached layout prop; it's stable for
    // the lifetime of this component in practice, and Klaro.setup() isn't
    // meant to be called more than once per page load anyway.
  }, []);

  if (codes.length === 0) return null;

  return (
    <>
      <KlaroTheme />
      {klaroModule && (
        <button
          type="button"
          onClick={() => klaroModule.show()}
          aria-label="Cookie-Einstellungen öffnen"
          title="Cookie-Einstellungen"
          className="fixed bottom-5 left-5 z-40 flex h-11 w-11 items-center justify-center rounded-full border border-border bg-bg-base shadow-md hover:border-brand transition-colors"
        >
          <svg viewBox="0 0 24 24" width="22" height="22" fill="none" aria-hidden="true">
            <circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.6" />
            <circle cx="9" cy="9.5" r="1.1" fill="currentColor" />
            <circle cx="14" cy="8.5" r="1" fill="currentColor" />
            <circle cx="15" cy="13.5" r="1.1" fill="currentColor" />
            <circle cx="10.5" cy="14.5" r="1" fill="currentColor" />
            <circle cx="12" cy="11" r="0.9" fill="currentColor" />
          </svg>
        </button>
      )}
    </>
  );
}
