"use client";

import Link from "next/link";
import Script from "next/script";
import { useEffect, useRef, useState, useSyncExternalStore } from "react";
import {
  denyAll,
  getAnalyticsId,
  grantAll,
  openConsentBanner,
  readConsentRaw,
  resolveConsent,
  subscribeToConsent,
  subscribeToConsentOpen,
  writeConsent,
  type ConsentChoices,
  type ConsentSource,
  type OptionalCategory,
} from "@/lib/consent";
import { routes } from "@/lib/routes";
import { cn } from "@/lib/cn";

const UNKNOWN = "__unknown__";

/** Reads consent from storage; renders "__unknown__" on the server so nothing flashes. */
export function useConsentRaw(): string | null {
  return useSyncExternalStore(subscribeToConsent, () => readConsentRaw(), () => UNKNOWN);
}

export function isConsentReady(raw: string | null): boolean {
  return raw !== UNKNOWN;
}

export interface ConsentCategory {
  id: "essential" | OptionalCategory;
  name: string;
  description: string;
  /** Categories the site cannot work without are shown, explained, and locked on. */
  always: boolean;
}

export const consentCategories: ConsentCategory[] = [
  {
    id: "essential",
    name: "Strictly necessary",
    description:
      "Remembers your cookie choice and your progress on resource checklists, and covers the security and load limits our hosting applies. Kept on your device and never sent to us.",
    always: true,
  },
  {
    id: "analytics",
    name: "Analytics",
    description:
      "Google Analytics 4, so we can see which pages are useful. It loads only if you allow it, and is set to deny advertising storage, so it is not used for advertising or remarketing.",
    always: false,
  },
];

/** A switch for one category. Locked categories render as a checked, disabled control. */
export function CategoryToggle({
  category,
  checked,
  onChange,
  className,
}: {
  category: ConsentCategory;
  checked: boolean;
  onChange?: (next: boolean) => void;
  className?: string;
}) {
  const inputId = `consent-${category.id}`;
  const descriptionId = `${inputId}-description`;

  return (
    <div className={cn("flex items-start justify-between gap-5", className)}>
      <div>
        <label htmlFor={inputId} className="text-[0.9375rem] font-medium text-ink">
          {category.name}
        </label>
        <p id={descriptionId} className="mt-2 text-sm text-ink-soft">
          {category.description}
        </p>
      </div>
      <div className="flex shrink-0 flex-col items-end gap-2">
        <span className="relative inline-flex h-6 w-11 shrink-0">
          <input
            id={inputId}
            type="checkbox"
            checked={checked}
            disabled={category.always}
            aria-describedby={descriptionId}
            onChange={(event) => onChange?.(event.target.checked)}
            className="peer absolute inset-0 z-10 size-full cursor-pointer opacity-0 disabled:cursor-default"
          />
          <span
            aria-hidden="true"
            className="absolute inset-0 rounded-full border border-line-strong bg-paper-deep transition-colors peer-checked:border-signal peer-checked:bg-signal peer-disabled:opacity-55 peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-signal"
          />
          <span
            aria-hidden="true"
            className="absolute left-0.5 top-0.5 size-5 rounded-full bg-surface transition-transform peer-checked:translate-x-5 peer-disabled:opacity-80"
          />
        </span>
        <span className="text-sm text-muted">{category.always ? "Always on" : checked ? "On" : "Off"}</span>
      </div>
    </div>
  );
}

/** Reopens the banner from anywhere. Without JavaScript it falls back to the preferences page. */
export function CookieSettingsLink({ className }: { className?: string }) {
  return (
    <Link
      href={routes.cookiePreferences}
      className={className}
      onClick={(event) => {
        if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
        event.preventDefault();
        openConsentBanner();
      }}
    >
      Cookie settings
    </Link>
  );
}

/** Sits above the sticky navbar (z-50), below the mobile nav sheet (z-60) and the skip link. */
const panelClassName =
  "fixed inset-x-3 bottom-3 z-[55] mx-auto max-h-[85vh] max-w-2xl overflow-y-auto rounded-lg border border-line bg-surface p-5 shadow-[0_24px_60px_-30px_rgba(16,16,20,0.45)] focus:outline-none sm:inset-x-6 sm:bottom-6 sm:p-6";

const buttonBase = "btn inline-flex h-11 items-center justify-center rounded-md px-4 text-[0.9375rem] font-medium";
const solidButton = `${buttonBase} bg-ink text-paper`;
const outlineButton = `${buttonBase} border border-line-strong text-ink hover:border-ink`;

export function ConsentManager() {
  const analyticsId = getAnalyticsId();
  const raw = useConsentRaw();
  const ready = isConsentReady(raw);
  const resolved = ready ? resolveConsent(raw) : null;

  const [reopened, setReopened] = useState(false);
  const [showDetail, setShowDetail] = useState(false);
  /** A toggle the visitor has moved but not saved. Null means "follow what is recorded". */
  const [pendingAnalytics, setPendingAnalytics] = useState<boolean | null>(null);
  const panelRef = useRef<HTMLDivElement>(null);
  const moveFocus = useRef(false);

  useEffect(
    () =>
      subscribeToConsentOpen(() => {
        moveFocus.current = true;
        setReopened(true);
      }),
    [],
  );

  const asking = resolved?.shouldAsk ?? false;
  const open = ready && (asking || reopened);
  const allowsAnalytics = resolved?.effective.analytics ?? false;
  const draft: ConsentChoices = { analytics: pendingAnalytics ?? allowsAnalytics };

  useEffect(() => {
    if (open && moveFocus.current) {
      moveFocus.current = false;
      panelRef.current?.focus();
    }
  }, [open]);

  const close = () => {
    setReopened(false);
    setShowDetail(false);
    setPendingAnalytics(null);
  };

  const decide = (choices: ConsentChoices, source: ConsentSource) => {
    writeConsent(choices, source);
    close();
  };

  return (
    <>
      {analyticsId && allowsAnalytics ? (
        <>
          <Script id="ga-consent" strategy="afterInteractive">
            {[
              "window.dataLayer=window.dataLayer||[];",
              "function gtag(){dataLayer.push(arguments);}",
              "window.gtag=window.gtag||gtag;",
              "gtag('consent','default',{ad_storage:'denied',ad_user_data:'denied',ad_personalization:'denied',analytics_storage:'denied'});",
              "gtag('consent','update',{analytics_storage:'granted'});",
              "gtag('js',new Date());",
              `gtag('config','${analyticsId}',{anonymize_ip:true});`,
            ].join("")}
          </Script>
          <Script src={`https://www.googletagmanager.com/gtag/js?id=${analyticsId}`} strategy="afterInteractive" />
        </>
      ) : null}

      {open ? (
        <div
          ref={panelRef}
          tabIndex={-1}
          role="dialog"
          aria-modal="false"
          aria-labelledby="consent-title"
          aria-describedby="consent-body"
          onKeyDown={(event) => {
            if (event.key === "Escape" && !asking) close();
          }}
          className={panelClassName}
        >
          <div className="flex items-start justify-between gap-4">
            <h2 id="consent-title" className="text-title">
              {analyticsId ? "Cookies on this site" : "Essential storage only"}
            </h2>
            {asking ? null : (
              <button
                type="button"
                onClick={close}
                className="-mr-1 -mt-1 inline-flex size-9 shrink-0 items-center justify-center rounded-md text-muted transition-colors hover:text-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-signal"
              >
                <span className="sr-only">Close cookie settings</span>
                <svg aria-hidden="true" viewBox="0 0 16 16" className="size-4" fill="none" stroke="currentColor" strokeWidth="1.5">
                  <path d="M3.5 3.5l9 9M12.5 3.5l-9 9" />
                </svg>
              </button>
            )}
          </div>

          <p id="consent-body" className="mt-3 text-[0.9375rem] text-ink-soft">
            {analyticsId ? (
              <>
                We use essential storage to make the site work, and we would like to use analytics to see which pages
                help visitors. Analytics loads only if you allow it, and you can change your mind at any time. The site
                sets no advertising cookies.
              </>
            ) : (
              <>
                This site currently uses essential storage only, so there is nothing optional to agree to. If that ever
                changes, you will be asked before anything loads.
              </>
            )}{" "}
            <Link href={routes.cookiePolicy} className="link-underline text-ink">
              Cookie policy
            </Link>
          </p>

          {showDetail ? (
            <div className="mt-5 divide-y divide-line border-y border-line">
              {consentCategories.map((category) => (
                <CategoryToggle
                  key={category.id}
                  category={category}
                  checked={category.always || draft[category.id as OptionalCategory]}
                  onChange={(next) => setPendingAnalytics(next)}
                  className="py-5"
                />
              ))}
            </div>
          ) : null}

          {analyticsId ? (
            <div className="mt-5 flex flex-wrap gap-2.5">
              {showDetail ? (
                <button type="button" onClick={() => decide(draft, "banner")} className={solidButton}>
                  Save choices
                </button>
              ) : null}
              <button type="button" onClick={() => decide(grantAll, "banner")} className={showDetail ? outlineButton : solidButton}>
                Accept all
              </button>
              <button type="button" onClick={() => decide(denyAll, "banner")} className={outlineButton}>
                Reject all
              </button>
              {showDetail ? null : (
                <button type="button" onClick={() => setShowDetail(true)} className={outlineButton}>
                  Manage preferences
                </button>
              )}
            </div>
          ) : (
            <div className="mt-5 flex flex-wrap gap-2.5">
              <button type="button" onClick={close} className={solidButton}>
                Close
              </button>
            </div>
          )}

          <p className="mt-4 text-sm text-muted">
            Full controls, including what each category stores, are on the{" "}
            <Link href={routes.cookiePreferences} className="link-underline-hover text-ink-soft hover:text-ink">
              cookie preferences
            </Link>{" "}
            page. Personal data is covered by our{" "}
            <Link href={routes.privacy} className="link-underline-hover text-ink-soft hover:text-ink">
              privacy policy
            </Link>
            .
          </p>
        </div>
      ) : null}
    </>
  );
}
