"use client";

import { invoke } from "@tauri-apps/api/core";
import { openUrl } from "@tauri-apps/plugin-opener";
import { useReducedMotion } from "motion/react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { LuArrowLeft, LuExternalLink, LuSearch } from "react-icons/lu";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { FadingScrollArea } from "@/components/ui/fading-scroll-area";
import { Input } from "@/components/ui/input";
import { StepTransition } from "@/components/ui/step-transition";
import licenses from "@/generated/licenses.json";
import xraySource from "@/generated/xray-source.json";
import { launchDonutClone } from "@/lib/donut-physics";
import { Logo } from "./icons/logo";
import { RippleButton } from "./ui/ripple";

interface AboutDialogProps {
  isOpen: boolean;
  onClose: () => void;
}

interface SystemInfo {
  app_version: string;
  os: string;
  arch: string;
  portable: boolean;
}

type AboutView = "about" | "licenses";

// Flywheel: each click adds spin; past this speed the donut escapes the
// dialog and bounces around the window (shared physics with the rail egg).
const SPIN_PER_CLICK = 540; // deg/s
const ESCAPE_VELOCITY = 2200; // deg/s
const SPIN_FRICTION = 1.1; // fraction of velocity lost per second

export function AboutDialog({ isOpen, onClose }: AboutDialogProps) {
  const { t } = useTranslation();
  const reducedMotion = useReducedMotion();
  const [systemInfo, setSystemInfo] = useState<SystemInfo | null>(null);
  const [logoFlown, setLogoFlown] = useState(false);
  const [view, setView] = useState<AboutView>("about");
  const [licenseQuery, setLicenseQuery] = useState("");

  const logoRef = useRef<HTMLButtonElement>(null);
  const rotationRef = useRef(0);
  const velocityRef = useRef(0);
  const rafRef = useRef(0);
  const lastTimeRef = useRef(0);
  const cancelLaunchRef = useRef<(() => void) | null>(null);
  const restoreLicensesButtonFocusRef = useRef(false);

  useEffect(() => {
    if (!isOpen) return;
    invoke<SystemInfo>("get_system_info")
      .then(setSystemInfo)
      .catch(() => {
        setSystemInfo(null);
      });
  }, [isOpen]);

  const stopSpin = useCallback(() => {
    if (rafRef.current) cancelAnimationFrame(rafRef.current);
    rafRef.current = 0;
    velocityRef.current = 0;
  }, []);

  const spinFrame = useCallback(
    (time: number) => {
      const el = logoRef.current;
      if (!el) {
        rafRef.current = 0;
        return;
      }
      const dt = Math.min((time - lastTimeRef.current) / 1000, 0.05);
      lastTimeRef.current = time;

      rotationRef.current += velocityRef.current * dt;
      velocityRef.current *= Math.max(0, 1 - SPIN_FRICTION * dt);
      el.style.transform = `rotate(${rotationRef.current}deg)`;

      if (velocityRef.current >= ESCAPE_VELOCITY) {
        // The flywheel wins: the donut tears loose and joins the bounce sim,
        // keeping its spin.
        stopSpin();
        setLogoFlown(true);
        cancelLaunchRef.current = launchDonutClone(el, {
          initialVX: Math.random() > 0.5 ? 420 : -420,
          initialVY: -750,
          spinSpeed: ESCAPE_VELOCITY,
          onExit: () => {
            cancelLaunchRef.current = null;
          },
        });
        return;
      }

      if (velocityRef.current > 5) {
        rafRef.current = requestAnimationFrame(spinFrame);
      } else {
        rafRef.current = 0;
        velocityRef.current = 0;
      }
    },
    [stopSpin],
  );

  const handleLogoClick = useCallback(() => {
    if (reducedMotion || logoFlown) return;
    velocityRef.current += SPIN_PER_CLICK;
    if (!rafRef.current) {
      lastTimeRef.current = performance.now();
      rafRef.current = requestAnimationFrame(spinFrame);
    }
  }, [reducedMotion, logoFlown, spinFrame]);

  const resetLogo = useCallback(() => {
    stopSpin();
    cancelLaunchRef.current?.();
    cancelLaunchRef.current = null;
    rotationRef.current = 0;
    if (logoRef.current) {
      logoRef.current.style.transform = "";
      logoRef.current.style.visibility = "";
    }
    setLogoFlown(false);
  }, [stopSpin]);

  const handleClose = useCallback(() => {
    resetLogo();
    setView("about");
    setLicenseQuery("");
    restoreLicensesButtonFocusRef.current = false;
    onClose();
  }, [onClose, resetLogo]);

  const handleLicensesButtonRef = useCallback(
    (node: HTMLButtonElement | null) => {
      if (node && restoreLicensesButtonFocusRef.current) {
        restoreLicensesButtonFocusRef.current = false;
        node.focus();
      }
    },
    [],
  );

  const handleOpenLicenses = useCallback(() => {
    resetLogo();
    setLicenseQuery("");
    setView("licenses");
  }, [resetLogo]);

  const handleBackToAbout = useCallback(() => {
    restoreLicensesButtonFocusRef.current = true;
    setLicenseQuery("");
    setView("about");
  }, []);

  const filteredLicenses = useMemo(() => {
    const query = licenseQuery.trim().toLocaleLowerCase();
    if (!query) return licenses;
    return licenses.filter(
      ({ name, license }) =>
        name.toLocaleLowerCase().includes(query) ||
        license.toLocaleLowerCase().includes(query),
    );
  }, [licenseQuery]);

  useEffect(() => {
    return () => {
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
      cancelLaunchRef.current?.();
    };
  }, []);

  return (
    <Dialog
      open={isOpen}
      onOpenChange={(open) => {
        if (!open) handleClose();
      }}
    >
      <DialogContent
        className={
          view === "licenses"
            ? "flex h-[min(80dvh,40rem)] max-w-lg flex-col overflow-hidden"
            : "max-w-sm"
        }
      >
        <StepTransition
          transitionKey={view}
          direction={view === "licenses" ? 1 : -1}
          className={
            view === "licenses"
              ? "flex min-h-0 flex-1 flex-col gap-4"
              : "grid gap-4"
          }
        >
          {view === "about" ? (
            <>
              <DialogHeader>
                <DialogTitle>{t("about.title")}</DialogTitle>
              </DialogHeader>

              <div className="flex flex-col items-center gap-3 py-4">
                <button
                  ref={logoRef}
                  type="button"
                  aria-label={t("header.donutLogo")}
                  onClick={handleLogoClick}
                  className="grid size-16 cursor-pointer place-items-center rounded-full bg-transparent text-foreground select-none will-change-transform"
                  style={logoFlown ? { visibility: "hidden" } : undefined}
                >
                  <Logo className="size-14" />
                </button>

                <div className="text-center">
                  <p className="text-lg font-semibold">Donut Browser</p>
                  {systemInfo && (
                    <>
                      <p className="text-sm text-muted-foreground">
                        {t("about.version", {
                          version: systemInfo.app_version,
                        })}
                        {systemInfo.portable && (
                          <span className="ml-1.5 rounded border border-border bg-muted px-1 py-px text-[10px] align-middle">
                            {t("about.portableBadge")}
                          </span>
                        )}
                      </p>
                      <p className="text-xs text-muted-foreground">
                        {systemInfo.os} {systemInfo.arch}
                      </p>
                    </>
                  )}
                </div>

                <p className="text-center text-xs text-muted-foreground">
                  {t("about.licenseNotice")}
                </p>

                <div className="flex flex-wrap justify-center gap-2">
                  <Button
                    variant="outline"
                    size="sm"
                    onClick={() => void openUrl("https://donutbrowser.com")}
                  >
                    {t("about.website")}
                  </Button>
                  <Button
                    variant="outline"
                    size="sm"
                    onClick={() =>
                      void openUrl("https://github.com/zhom/donutbrowser")
                    }
                  >
                    {t("about.github")}
                  </Button>
                  <Button
                    ref={handleLicensesButtonRef}
                    variant="outline"
                    size="sm"
                    onClick={handleOpenLicenses}
                  >
                    {t("about.licenses")}
                  </Button>
                </div>
              </div>

              <div className="flex justify-end">
                <RippleButton variant="outline" onClick={handleClose}>
                  {t("common.buttons.close")}
                </RippleButton>
              </div>
            </>
          ) : (
            <>
              <DialogHeader className="flex-row items-center gap-2">
                <Button
                  type="button"
                  variant="ghost"
                  size="icon"
                  className="-ml-2 size-8"
                  aria-label={t("common.buttons.back")}
                  onClick={handleBackToAbout}
                >
                  <LuArrowLeft aria-hidden="true" />
                </Button>
                <DialogTitle>{t("about.licenses")}</DialogTitle>
              </DialogHeader>

              <div className="relative shrink-0">
                <LuSearch
                  aria-hidden="true"
                  className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground"
                />
                <Input
                  autoFocus
                  type="search"
                  value={licenseQuery}
                  onChange={(event) => {
                    setLicenseQuery(event.target.value);
                  }}
                  aria-label={t("about.searchLicenses")}
                  placeholder={t("about.searchLicenses")}
                  className="pl-9"
                />
              </div>

              <FadingScrollArea
                role="region"
                tabIndex={0}
                aria-label={t("about.licenses")}
                className="-mx-2 min-h-0 flex-1 rounded-md px-2 outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50"
              >
                {filteredLicenses.length > 0 ? (
                  <ul>
                    {filteredLicenses.map(({ name, license }) => (
                      <li
                        key={`${name}-${license}`}
                        className="grid grid-cols-[minmax(0,1fr)_minmax(7rem,45%)] items-baseline gap-3 border-b border-border/60 py-2.5 last:border-b-0"
                      >
                        {name === "Xray-core" ? (
                          <button
                            type="button"
                            onClick={() => void openUrl(xraySource.sourceUrl)}
                            aria-label={t("about.openSource", { name })}
                            title={t("about.openSource", { name })}
                            className="flex min-w-0 items-center gap-1.5 rounded-sm text-left text-sm font-medium text-foreground underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 active:scale-[0.98] motion-reduce:transform-none"
                          >
                            <span className="truncate">{name}</span>
                            <LuExternalLink
                              aria-hidden="true"
                              className="size-3.5 shrink-0 text-muted-foreground"
                            />
                          </button>
                        ) : (
                          <span
                            className="truncate text-sm font-medium text-foreground"
                            title={name}
                          >
                            {name}
                          </span>
                        )}
                        <code className="break-words text-right text-xs text-muted-foreground">
                          {license}
                        </code>
                      </li>
                    ))}
                  </ul>
                ) : (
                  <p
                    role="status"
                    className="py-12 text-center text-sm text-muted-foreground"
                  >
                    {t("about.noMatchingLicenses")}
                  </p>
                )}
              </FadingScrollArea>
            </>
          )}
        </StepTransition>
      </DialogContent>
    </Dialog>
  );
}
