import { useEffect, useState } from "react";
import { emitTo } from "@tauri-apps/api/event";

import {
  hidePanel,
  quitApp,
  scrapeSubscriptions,
  showMainWindow,
  traySaveVideo,
} from "../api";
import { Spinner } from "./ui";

/**
 * The menu bar panel.
 *
 * A window rather than a native menu, so it is the app's own type, spacing and
 * colours instead of the system's. It hangs from the icon and closes when it
 * loses focus, which is what a menu does; everything else about it is ours.
 */

interface RowProps {
  label: string;
  hint?: string;
  onClick: () => void;
  busy?: boolean;
  icon: React.ReactNode;
}

function Row({ label, hint, onClick, busy, icon }: RowProps) {
  return (
    <button
      onClick={onClick}
      disabled={busy}
      className="flex w-full cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1.5 text-left
                 transition-colors hover:bg-slate-100 disabled:cursor-wait
                 dark:hover:bg-slate-800"
    >
      <span className="grid size-6 shrink-0 place-items-center text-slate-400 dark:text-slate-500">
        {busy ? <Spinner className="size-3.5" /> : icon}
      </span>
      <span className="min-w-0">
        <span className="block truncate text-[12.5px] font-medium text-slate-700 dark:text-slate-200">
          {label}
        </span>
        {hint && (
          <span className="block truncate text-[11px] text-slate-400 dark:text-slate-500">
            {hint}
          </span>
        )}
      </span>
    </button>
  );
}

const ICON = "size-4";
const stroke = { fill: "none", stroke: "currentColor", strokeWidth: 1.8 } as const;

export default function TrayPanel() {
  const [busy, setBusy] = useState<string | null>(null);
  const [note, setNote] = useState<string | null>(null);

  // The panel is its own window, so it carries no page background of the app's.
  useEffect(() => {
    document.documentElement.style.background = "transparent";
    document.body.style.background = "transparent";
  }, []);

  const run = (id: string, fn: () => Promise<unknown>, closeAfter = true) => {
    setBusy(id);
    setNote(null);
    fn()
      .then(() => {
        if (closeAfter) void hidePanel();
      })
      .catch((e) => setNote(String(e)))
      .finally(() => setBusy(null));
  };

  const importSubscriptions = () =>
    run(
      "subs",
      async () => {
        const result = await scrapeSubscriptions();
        // The window owns the confirmation: replacing the list is not a thing
        // to agree to in a panel that closes when you look away.
        await emitTo("main", "subs:scraped", result);
        await showMainWindow();
      },
      false,
    );

  return (
    <div
      className="flex h-screen w-screen flex-col rounded-xl border border-slate-300 bg-white/95
                 p-1.5 shadow-2xl backdrop-blur-xl dark:border-slate-700 dark:bg-slate-900/95"
    >
      <div className="px-2 pb-1 pt-1.5 text-[10px] font-bold uppercase tracking-widest text-slate-400">
        FlightTube
      </div>

      <Row
        label="Download this video"
        hint="From the browser it is playing in"
        busy={busy === "video"}
        onClick={() => run("video", traySaveVideo)}
        icon={
          <svg viewBox="0 0 24 24" className={ICON} {...stroke} strokeLinecap="round" strokeLinejoin="round">
            <path d="M12 4v10.5M7.5 10l4.5 4.5 4.5-4.5M4 18.5v1A2.5 2.5 0 006.5 22h11a2.5 2.5 0 002.5-2.5v-1" />
          </svg>
        }
      />
      <Row
        label="Import subscriptions"
        hint="Read them off your YouTube page"
        busy={busy === "subs"}
        onClick={importSubscriptions}
        icon={
          <svg viewBox="0 0 24 24" className={ICON} {...stroke} strokeLinecap="round" strokeLinejoin="round">
            <path d="M4 7h9M4 12h9M4 17h5" />
            <path d="M17 9v8m0 0l-2.5-2.5M17 17l2.5-2.5" />
          </svg>
        }
      />

      <Row
        label="Remove all downloads"
        hint="Asks in the window first"
        busy={busy === "wipe"}
        onClick={() =>
          run(
            "wipe",
            async () => {
              await emitTo("main", "downloads:wipe-request", null);
              await showMainWindow();
            },
            false,
          )
        }
        icon={
          <svg viewBox="0 0 24 24" className={ICON} {...stroke} strokeLinecap="round" strokeLinejoin="round">
            <path d="M4 7h16M10 11v6M14 11v6" />
            <path d="M6 7l1 12.5A1.5 1.5 0 008.5 21h7a1.5 1.5 0 001.5-1.5L18 7" />
            <path d="M9 7V5a1 1 0 011-1h4a1 1 0 011 1v2" />
          </svg>
        }
      />

      <div className="my-1 h-px bg-slate-200 dark:bg-slate-800" />

      <Row
        label="Open FlightTube"
        onClick={() => run("open", async () => showMainWindow())}
        icon={
          <svg viewBox="0 0 24 24" className={ICON} {...stroke} strokeLinecap="round" strokeLinejoin="round">
            <rect x="3.5" y="5" width="17" height="14" rx="2" />
            <path d="M9 5v14" />
          </svg>
        }
      />
      <Row
        label="Quit"
        onClick={() => void quitApp()}
        icon={
          <svg viewBox="0 0 24 24" className={ICON} {...stroke} strokeLinecap="round" strokeLinejoin="round">
            <path d="M15 5h3a2 2 0 012 2v10a2 2 0 01-2 2h-3M10 12H3m0 0l3.5-3.5M3 12l3.5 3.5" />
          </svg>
        }
      />

      {note && (
        <p
          className="mt-1 max-h-16 overflow-y-auto rounded-lg bg-red-500/10 px-2 py-1.5 text-[11px]
                     leading-snug text-red-700 dark:text-red-300"
        >
          {note}
        </p>
      )}
    </div>
  );
}
