import { useEffect, useMemo, useState } from "react";
import { useRouter } from "@tanstack/react-router";
import { toast } from "sonner";
import { Photo } from "@/components/site/look";
import { Button, Field, Input, TextArea } from "@/components/ui";
import { getSiteLook, saveSiteLook, uploadSiteFile } from "@/lib/clinic/api";
import { LOCALES, type Locale } from "@/lib/clinic/locale";
import { MEDIA_SLOTS, THEME_DEFAULT } from "@/lib/clinic/media";
import type { Theme } from "@/lib/clinic/types";
import { DICTS, tPath } from "@/lib/i18n";
import { useI18n } from "@/lib/i18n/context";

const COLOR_KEYS = ["forest", "forestDeep", "ivory", "paper", "gold", "goldDeep", "charcoal", "sage", "muted", "line"] as const;

function flatten(value: unknown, prefix = ""): string[] {
  if (typeof value === "string") return prefix ? [prefix] : [];
  if (!value || typeof value !== "object") return [];
  return Object.entries(value).flatMap(([key, child]) => flatten(child, prefix ? `${prefix}.${key}` : key));
}

async function toBase64(file: File) {
  const bytes = new Uint8Array(await file.arrayBuffer());
  let binary = "";
  for (let i = 0; i < bytes.length; i += 0x8000) binary += String.fromCharCode(...bytes.subarray(i, i + 0x8000));
  return btoa(binary);
}

export function Studio() {
  const { t, locale } = useI18n();
  const router = useRouter();
  const [tab, setTab] = useState<"colors" | "pictures" | "texts" | "font">("colors");
  const [theme, setTheme] = useState<Theme>(THEME_DEFAULT);
  const [media, setMedia] = useState<Record<string, string>>({});
  const [copy, setCopy] = useState<Record<string, Record<string, string>>>({});
  const [fontUrl, setFontUrl] = useState("");
  const [lang, setLang] = useState<Locale>(locale);
  const [query, setQuery] = useState("");
  const [ready, setReady] = useState(false);
  const paths = useMemo(() => flatten(DICTS.en), []);
  useEffect(() => {
    let live = true;
    void getSiteLook().then((look) => {
      if (!live) return;
      setTheme(look.theme);
      setMedia(look.media ?? {});
      setCopy(look.copy ?? {});
      setFontUrl(look.fontUrl ?? "");
      setReady(true);
    });
    return () => { live = false; };
  }, []);

  async function refresh() {
    await router.invalidate();
  }

  const shown = paths.filter((path) => {
    const value = copy[lang]?.[path] || tPath(DICTS[lang], path);
    const needle = query.trim().toLowerCase();
    return !needle || path.toLowerCase().includes(needle) || value.toLowerCase().includes(needle);
  }).slice(0, 24);

  if (!ready) return <p className="text-sm text-muted">{t("common.loading")}</p>;

  return (
    <div className="grid gap-4">
      <div className="flex flex-wrap gap-2">
        {(["colors", "pictures", "texts", "font"] as const).map((id) => (
          <button key={id} type="button" className={`h-11 rounded-full px-4 text-sm ${tab === id ? "bg-forest text-ivory" : "bg-paper"}`} onClick={() => setTab(id)}>{t(`admin.${id}`)}</button>
        ))}
      </div>

      {tab === "colors" ? (
        <form className="grid max-w-xl gap-3" onSubmit={async (event) => {
          event.preventDefault();
          const result = await saveSiteLook({ data: { theme } });
          if (!result.ok) { toast.error(t(`errors.${result.error}`)); return; }
          toast.success(t("common.saved"));
          await refresh();
        }}>
          <div className="grid grid-cols-2 gap-3">
            {COLOR_KEYS.map((key) => (
              <Field key={key} label={key}>
                <span className="flex items-center gap-2">
                  <input type="color" className="size-11 rounded-xl border border-line bg-ivory" value={theme[key]} onChange={(event) => {
                    const next = { ...theme, [key]: event.target.value };
                    setTheme(next);
                    document.documentElement.style.setProperty(`--color-${key.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}`, event.target.value);
                  }} />
                  <Input value={theme[key]} onChange={(event) => setTheme({ ...theme, [key]: event.target.value })} />
                </span>
              </Field>
            ))}
          </div>
          <Button type="submit">{t("common.save")}</Button>
        </form>
      ) : null}

      {tab === "pictures" ? (
        <div className="grid grid-cols-2 gap-3 md:grid-cols-3">
          {MEDIA_SLOTS.map((slot) => (
            <article key={slot.key} className="rounded-[1.35rem] bg-paper p-2">
              <Photo src={media[slot.key] || slot.key} alt="" className="aspect-square w-full rounded-2xl object-cover" />
              <p className="px-1 py-2 text-sm text-forest">{locale === "en" ? slot.en : slot.fa}</p>
              <label className="flex h-11 cursor-pointer items-center justify-center rounded-full bg-forest text-sm text-ivory">
                {t("admin.upload")}
                <input type="file" accept="image/jpeg,image/png,image/webp" className="sr-only" onChange={async (event) => {
                  const file = event.target.files?.[0];
                  event.target.value = "";
                  if (!file) return;
                  if (file.size > 1_200_000) { toast.error(t("errors.invalid")); return; }
                  const uploaded = await uploadSiteFile({ data: { data: await toBase64(file), kind: "image" } });
                  if (!uploaded.ok) { toast.error(t(`errors.${uploaded.error}`)); return; }
                  const saved = await saveSiteLook({ data: { mediaKey: slot.key, mediaUrl: uploaded.url } });
                  if (!saved.ok) { toast.error(t(`errors.${saved.error}`)); return; }
                  setMedia(saved.media);
                  toast.success(t("common.saved"));
                  await refresh();
                }} />
              </label>
              {media[slot.key] ? <button type="button" className="mt-2 h-10 w-full text-xs text-muted" onClick={async () => {
                const saved = await saveSiteLook({ data: { mediaKey: slot.key, mediaUrl: "" } });
                if (!saved.ok) return;
                setMedia(saved.media);
                await refresh();
              }}>{t("admin.resetLook")}</button> : null}
            </article>
          ))}
        </div>
      ) : null}

      {tab === "texts" ? (
        <div className="grid max-w-3xl gap-3">
          <div className="flex flex-wrap gap-2">
            {LOCALES.map((code) => (
              <button key={code} type="button" className={`h-10 rounded-full px-3 text-sm ${lang === code ? "bg-forest text-ivory" : "bg-paper"}`} onClick={() => setLang(code)}>{code}</button>
            ))}
          </div>
          <Field label={t("admin.searchText")}><Input value={query} onChange={(event) => setQuery(event.target.value)} /></Field>
          {shown.map((path) => (
            <Field key={`${lang}-${path}`} label={path}>
              <TextArea defaultValue={copy[lang]?.[path] || tPath(DICTS[lang], path)} onBlur={async (event) => {
                const value = event.target.value;
                const current = copy[lang]?.[path] || tPath(DICTS[lang], path);
                if (value === current) return;
                const saved = await saveSiteLook({ data: { locale: lang, path, text: value } });
                if (!saved.ok) { toast.error(t(`errors.${saved.error}`)); return; }
                setCopy(saved.copy);
                toast.success(t("common.saved"));
                await refresh();
              }} />
            </Field>
          ))}
        </div>
      ) : null}

      {tab === "font" ? (
        <div className="grid max-w-xl gap-3">
          <p className="text-sm text-muted">{t("admin.fontNote")}</p>
          <p className="font-display text-3xl">اورلیا Aurelia 123</p>
          <label className="flex h-12 cursor-pointer items-center justify-center rounded-full bg-forest text-ivory">
            {t("admin.upload")} woff2
            <input type="file" accept=".woff2,font/woff2" className="sr-only" onChange={async (event) => {
              const file = event.target.files?.[0];
              event.target.value = "";
              if (!file) return;
              if (file.size > 1_200_000) { toast.error(t("errors.invalid")); return; }
              const uploaded = await uploadSiteFile({ data: { data: await toBase64(file), kind: "font" } });
              if (!uploaded.ok) { toast.error(t(`errors.${uploaded.error}`)); return; }
              const saved = await saveSiteLook({ data: { fontUrl: uploaded.url } });
              if (!saved.ok) { toast.error(t(`errors.${saved.error}`)); return; }
              setFontUrl(saved.fontUrl);
              toast.success(t("common.saved"));
              window.location.reload();
            }} />
          </label>
          {fontUrl ? <button type="button" className="h-11 text-sm text-muted" onClick={async () => {
            await saveSiteLook({ data: { fontUrl: "" } });
            window.location.reload();
          }}>{t("admin.resetLook")}</button> : null}
        </div>
      ) : null}
    </div>
  );
}
