import {
  Check,
  Clipboard,
  FileDown,
  FileInput,
  Languages,
  Plus,
  RefreshCcw,
  Settings,
  ShieldCheck,
  SunMoon,
  Trash2,
  X
} from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import type { ReactNode } from "react";
import packageInfo from "../package.json";
import { transformEnv } from "./env";
import type { EnvDefault } from "./env";

type ThemeMode = "system" | "light" | "dark";
type Language = "de" | "en" | "es" | "fr" | "nl";

const initialDefaults: EnvDefault[] = [{ key: "BOOTSTRAP_ADMIN_EMAIL", value: "admin@example.local" }];

const languageNames: Record<Language, string> = {
  de: "Deutsch",
  en: "English",
  es: "Español",
  fr: "Français",
  nl: "Nederlands"
};

const translations = {
  de: {
    appSubtitle: "Lokaler Helfer für .env Vorlagen",
    loadFile: "Datei laden",
    saveFile: ".env speichern",
    settings: "Einstellungen",
    input: "Input",
    output: "Output",
    inputHint: "Datei laden oder Text direkt bearbeiten",
    outputHint: "Generierte .env, bereit zum Kopieren",
    copy: "Kopieren",
    copied: "Kopiert",
    regenerate: "Neu erzeugen",
    hits: "Fundstellen",
    values: "Werte",
    defaultsApplied: "Defaults",
    source: "Quelle",
    text: "Text",
    defaults: "Standardwerte",
    defaultsHint: "Diese Werte überschreiben passende Keys im Output.",
    addDefault: "Standardwert hinzufügen",
    key: "Key",
    value: "Wert",
    detected: "Erkannte Anforderungen",
    detectedHint: "Placeholder, betroffene Keys und erzeugtes Format.",
    placeholder: "Placeholder",
    keys: "Keys",
    format: "Format",
    noPlaceholders: "Keine CHANGE_ME Platzhalter gefunden.",
    language: "Sprache",
    theme: "Darstellung",
    system: "System",
    light: "Hell",
    dark: "Dunkel",
    version: "Version",
    author: "Autor",
    repository: "Repository"
  },
  en: {
    appSubtitle: "Local helper for .env templates",
    loadFile: "Load file",
    saveFile: "Save .env",
    settings: "Settings",
    input: "Input",
    output: "Output",
    inputHint: "Load a file or edit text directly",
    outputHint: "Generated .env, ready to copy",
    copy: "Copy",
    copied: "Copied",
    regenerate: "Regenerate",
    hits: "Matches",
    values: "Values",
    defaultsApplied: "Defaults",
    source: "Source",
    text: "Text",
    defaults: "Defaults",
    defaultsHint: "These values override matching keys in the output.",
    addDefault: "Add default",
    key: "Key",
    value: "Value",
    detected: "Detected requirements",
    detectedHint: "Placeholder, affected keys, and generated format.",
    placeholder: "Placeholder",
    keys: "Keys",
    format: "Format",
    noPlaceholders: "No CHANGE_ME placeholders found.",
    language: "Language",
    theme: "Appearance",
    system: "System",
    light: "Light",
    dark: "Dark",
    version: "Version",
    author: "Author",
    repository: "Repository"
  },
  es: {
    appSubtitle: "Ayudante local para plantillas .env",
    loadFile: "Cargar archivo",
    saveFile: "Guardar .env",
    settings: "Ajustes",
    input: "Entrada",
    output: "Salida",
    inputHint: "Carga un archivo o edita el texto",
    outputHint: ".env generado, listo para copiar",
    copy: "Copiar",
    copied: "Copiado",
    regenerate: "Regenerar",
    hits: "Coincidencias",
    values: "Valores",
    defaultsApplied: "Defaults",
    source: "Origen",
    text: "Texto",
    defaults: "Valores predeterminados",
    defaultsHint: "Estos valores sobrescriben claves iguales en la salida.",
    addDefault: "Añadir valor",
    key: "Clave",
    value: "Valor",
    detected: "Requisitos detectados",
    detectedHint: "Placeholder, claves afectadas y formato generado.",
    placeholder: "Placeholder",
    keys: "Claves",
    format: "Formato",
    noPlaceholders: "No se encontraron placeholders CHANGE_ME.",
    language: "Idioma",
    theme: "Apariencia",
    system: "Sistema",
    light: "Claro",
    dark: "Oscuro",
    version: "Versión",
    author: "Autor",
    repository: "Repositorio"
  },
  fr: {
    appSubtitle: "Assistant local pour modèles .env",
    loadFile: "Charger",
    saveFile: "Enregistrer .env",
    settings: "Réglages",
    input: "Entrée",
    output: "Sortie",
    inputHint: "Chargez un fichier ou modifiez le texte",
    outputHint: ".env généré, prêt à copier",
    copy: "Copier",
    copied: "Copié",
    regenerate: "Régénérer",
    hits: "Occurrences",
    values: "Valeurs",
    defaultsApplied: "Défauts",
    source: "Source",
    text: "Texte",
    defaults: "Valeurs par défaut",
    defaultsHint: "Ces valeurs remplacent les clés correspondantes dans la sortie.",
    addDefault: "Ajouter",
    key: "Clé",
    value: "Valeur",
    detected: "Exigences détectées",
    detectedHint: "Placeholder, clés concernées et format généré.",
    placeholder: "Placeholder",
    keys: "Clés",
    format: "Format",
    noPlaceholders: "Aucun placeholder CHANGE_ME trouvé.",
    language: "Langue",
    theme: "Apparence",
    system: "Système",
    light: "Clair",
    dark: "Sombre",
    version: "Version",
    author: "Auteur",
    repository: "Dépôt"
  },
  nl: {
    appSubtitle: "Lokale helper voor .env sjablonen",
    loadFile: "Bestand laden",
    saveFile: ".env opslaan",
    settings: "Instellingen",
    input: "Input",
    output: "Output",
    inputHint: "Laad een bestand of bewerk tekst direct",
    outputHint: "Gegenereerde .env, klaar om te kopiëren",
    copy: "Kopiëren",
    copied: "Gekopieerd",
    regenerate: "Opnieuw maken",
    hits: "Treffers",
    values: "Waarden",
    defaultsApplied: "Defaults",
    source: "Bron",
    text: "Tekst",
    defaults: "Standaardwaarden",
    defaultsHint: "Deze waarden overschrijven gelijke keys in de output.",
    addDefault: "Waarde toevoegen",
    key: "Key",
    value: "Waarde",
    detected: "Gedetecteerde eisen",
    detectedHint: "Placeholder, betrokken keys en gegenereerd formaat.",
    placeholder: "Placeholder",
    keys: "Keys",
    format: "Formaat",
    noPlaceholders: "Geen CHANGE_ME placeholders gevonden.",
    language: "Taal",
    theme: "Weergave",
    system: "Systeem",
    light: "Licht",
    dark: "Donker",
    version: "Versie",
    author: "Auteur",
    repository: "Repository"
  }
} satisfies Record<Language, Record<string, string>>;

const themeLabels: ThemeMode[] = ["system", "light", "dark"];

function detectLanguage(): Language {
  const stored = localStorage.getItem("envhelper-language") as Language | null;
  if (stored && stored in languageNames) {
    return stored;
  }

  const browserLanguage = navigator.language.slice(0, 2) as Language;
  return browserLanguage in languageNames ? browserLanguage : "de";
}

function readDefaults(): EnvDefault[] {
  const stored = localStorage.getItem("envhelper-defaults");
  if (!stored) {
    return initialDefaults;
  }

  try {
    const parsed = JSON.parse(stored) as EnvDefault[];
    return Array.isArray(parsed) ? parsed : initialDefaults;
  } catch {
    return initialDefaults;
  }
}

function readTheme(): ThemeMode {
  const stored = localStorage.getItem("envhelper-theme") as ThemeMode | null;
  return stored && themeLabels.includes(stored) ? stored : "system";
}

export default function App() {
  const [input, setInput] = useState("");
  const [loadedPath, setLoadedPath] = useState<string | null>(null);
  const [copyLabel, setCopyLabel] = useState<"copy" | "copied">("copy");
  const [generation, setGeneration] = useState(0);
  const [settingsOpen, setSettingsOpen] = useState(false);
  const [themeMode, setThemeMode] = useState<ThemeMode>(readTheme);
  const [language, setLanguage] = useState<Language>(detectLanguage);
  const [defaults, setDefaults] = useState<EnvDefault[]>(readDefaults);
  const t = translations[language];
  const result = useMemo(() => transformEnv(input, defaults), [input, defaults, generation]);

  useEffect(() => {
    document.documentElement.dataset.theme = themeMode;
    localStorage.setItem("envhelper-theme", themeMode);
  }, [themeMode]);

  useEffect(() => {
    localStorage.setItem("envhelper-language", language);
  }, [language]);

  useEffect(() => {
    localStorage.setItem("envhelper-defaults", JSON.stringify(defaults));
  }, [defaults]);

  async function openFile() {
    const file = await window.envHelper?.openFile();
    if (file) {
      setInput(file.content);
      setLoadedPath(file.path);
    }
  }

  async function saveFile() {
    await window.envHelper?.saveFile(result.output);
  }

  async function copyOutput() {
    await navigator.clipboard.writeText(result.output);
    setCopyLabel("copied");
    window.setTimeout(() => setCopyLabel("copy"), 1400);
  }

  function updateDefault(index: number, field: keyof EnvDefault, value: string) {
    setDefaults((current) => current.map((entry, entryIndex) => (entryIndex === index ? { ...entry, [field]: value } : entry)));
  }

  function addDefault() {
    setDefaults((current) => [...current, { key: "", value: "" }]);
  }

  function removeDefault(index: number) {
    setDefaults((current) => current.filter((_, entryIndex) => entryIndex !== index));
  }

  return (
    <main className="appShell">
      <header className="toolbar">
        <div className="brand">
          <div className="brandMark">EH</div>
          <div>
            <h1>EnvHelper</h1>
            <p>{t.appSubtitle}</p>
          </div>
        </div>

        <div className="toolbarActions">
          <button className="secondary" onClick={openFile} type="button">
            <FileInput size={17} /> {t.loadFile}
          </button>
          <button className="secondary" onClick={saveFile} type="button" disabled={!result.output}>
            <FileDown size={17} /> {t.saveFile}
          </button>
          <div className="segmented" aria-label={t.theme}>
            {themeLabels.map((mode) => (
              <button
                className={themeMode === mode ? "active" : ""}
                key={mode}
                onClick={() => setThemeMode(mode)}
                type="button"
                title={t[mode]}
              >
                {mode === "system" ? <SunMoon size={15} /> : t[mode]}
              </button>
            ))}
          </div>
          <button className="iconButton" onClick={() => setSettingsOpen(true)} title={t.settings} type="button">
            <Settings size={18} />
          </button>
        </div>
      </header>

      <section className="statusStrip">
        <Stat label={t.hits} value={String(result.changedCount)} />
        <Stat label={t.values} value={String(result.replacements.length)} />
        <Stat label={t.defaultsApplied} value={String(result.defaultedKeys.length)} />
        <Stat label={t.source} value={loadedPath ? "Datei" : t.text} />
      </section>

      <section className="workbench">
        <EditorPanel
          hint={loadedPath ?? t.inputHint}
          title={t.input}
        >
          <textarea spellCheck={false} value={input} onChange={(event) => setInput(event.target.value)} aria-label="Env input" />
        </EditorPanel>

        <EditorPanel
          actions={
            <>
              <button className="iconButton" onClick={() => setGeneration((current) => current + 1)} title={t.regenerate} type="button">
                <RefreshCcw size={17} />
              </button>
              <button className="primary" onClick={copyOutput} type="button">
                {copyLabel === "copied" ? <Check size={17} /> : <Clipboard size={17} />} {copyLabel === "copied" ? t.copied : t.copy}
              </button>
            </>
          }
          hint={t.outputHint}
          title={t.output}
        >
          <textarea spellCheck={false} value={result.output} readOnly aria-label="Env output" />
        </EditorPanel>
      </section>

      <section className="lowerGrid">
        <section className="dataPanel">
          <PanelHeading icon={<Plus size={18} />} title={t.defaults} hint={t.defaultsHint} />
          <div className="defaultsList">
            {defaults.map((entry, index) => (
              <div className="defaultRow" key={index}>
                <input
                  aria-label={t.key}
                  placeholder={t.key}
                  value={entry.key}
                  onChange={(event) => updateDefault(index, "key", event.target.value)}
                />
                <input
                  aria-label={t.value}
                  placeholder={t.value}
                  value={entry.value}
                  onChange={(event) => updateDefault(index, "value", event.target.value)}
                />
                <button className="iconButton subtle" onClick={() => removeDefault(index)} title="Remove" type="button">
                  <Trash2 size={16} />
                </button>
              </div>
            ))}
          </div>
          <button className="secondary fullWidth" onClick={addDefault} type="button">
            <Plus size={17} /> {t.addDefault}
          </button>
        </section>

        <section className="dataPanel">
          <PanelHeading icon={<ShieldCheck size={18} />} title={t.detected} hint={t.detectedHint} />
          {result.replacements.length === 0 ? (
            <div className="empty">{t.noPlaceholders}</div>
          ) : (
            <div className="requirementsTable">
              <div className="tableHeader">
                <span>{t.placeholder}</span>
                <span>{t.keys}</span>
                <span>{t.format}</span>
              </div>
              {result.replacements.map((replacement) => (
                <div className="tableRow" key={replacement.placeholder}>
                  <code>{replacement.placeholder}</code>
                  <span>{replacement.keys.join(", ")}</span>
                  <strong>{replacement.format}</strong>
                </div>
              ))}
            </div>
          )}
        </section>
      </section>

      {settingsOpen ? (
        <aside className="settingsOverlay" aria-label={t.settings}>
          <div className="settingsPanel">
            <div className="settingsHeader">
              <div>
                <h2>{t.settings}</h2>
                <p>{t.appSubtitle}</p>
              </div>
              <button className="iconButton" onClick={() => setSettingsOpen(false)} title="Close" type="button">
                <X size={18} />
              </button>
            </div>

            <div className="settingsGroup">
              <label>
                <Languages size={18} /> {t.language}
              </label>
              <div className="languageGrid">
                {(Object.keys(languageNames) as Language[]).map((code) => (
                  <button className={language === code ? "selected" : ""} key={code} onClick={() => setLanguage(code)} type="button">
                    {languageNames[code]}
                  </button>
                ))}
              </div>
            </div>

            <div className="settingsMeta">
              <span>{t.version}: {packageInfo.version}</span>
              <span>{t.author}: {packageInfo.author}</span>
              <span>{t.repository}: MrSphay/envHelper</span>
            </div>
          </div>
        </aside>
      ) : null}
    </main>
  );
}

function Stat({ label, value }: { label: string; value: string }) {
  return (
    <div className="statItem">
      <span>{value}</span>
      <p>{label}</p>
    </div>
  );
}

function EditorPanel({ actions, children, hint, title }: { actions: ReactNode; children: ReactNode; hint: string; title: string }) {
  return (
    <section className="editorPanel">
      <div className="panelHeader">
        <div>
          <h2>{title}</h2>
          <p>{hint}</p>
        </div>
        <div className="buttonRow">{actions}</div>
      </div>
      {children}
    </section>
  );
}

function PanelHeading({ hint, icon, title }: { hint: string; icon: ReactNode; title: string }) {
  return (
    <div className="panelHeading">
      <div>
        <h2>{title}</h2>
        <p>{hint}</p>
      </div>
      {icon}
    </div>
  );
}
