/* ================================================
   App — Main shell with view switching + API persistence
================================================ */

/* ---------- URL-Router ---------- */
// Abbildung Pfad ↔ App-State. Unterstützte Routen:
//   /                         -> Liste
//   /karte                    -> Karte
//   /einstellungen            -> Einstellungen
//   /neu                      -> Liste + Wizard (neu)
//   /flaeche/{id}             -> Detail einer Parzelle
//   /flaeche/{id}/bearbeiten  -> Detail + Wizard (edit)
function parseRoute(path) {
  const p = (path || "/").replace(/\/+$/, "") || "/";
  if (p === "/" || p === "/flaechen") return { view: "list", selectedId: null, wizardMode: null };
  if (p === "/karte") return { view: "map", selectedId: null, wizardMode: null };
  if (p === "/einstellungen") return { view: "settings", selectedId: null, wizardMode: null };
  if (p === "/neu") return { view: "list", selectedId: null, wizardMode: "new" };
  const m = p.match(/^\/flaeche\/([^/]+?)(\/bearbeiten)?$/);
  if (m) {
    return {
      view: "detail",
      selectedId: decodeURIComponent(m[1]),
      wizardMode: m[2] ? "edit" : null,
    };
  }
  return { view: "list", selectedId: null, wizardMode: null };
}

function buildPath(view, selectedId, wizardMode) {
  if (wizardMode === "new") return "/neu";
  if (view === "detail" && selectedId) {
    return `/flaeche/${encodeURIComponent(selectedId)}${wizardMode === "edit" ? "/bearbeiten" : ""}`;
  }
  if (view === "map") return "/karte";
  if (view === "settings") return "/einstellungen";
  return "/";
}

const api = {
  async get(path) {
    const r = await fetch(path, { headers: { Accept: "application/json" } });
    if (!r.ok) throw new Error(`GET ${path} failed: ${r.status}`);
    return r.json();
  },
  async send(method, path, body) {
    const r = await fetch(path, {
      method,
      headers: { "Content-Type": "application/json", Accept: "application/json" },
      body: body ? JSON.stringify(body) : undefined,
    });
    if (!r.ok && r.status !== 204) {
      const err = await r.text();
      throw new Error(`${method} ${path} failed: ${r.status} ${err}`);
    }
    if (r.status === 204) return null;
    return r.json();
  },
  post(path, body) { return this.send("POST", path, body); },
  put(path, body) { return this.send("PUT", path, body); },
  del(path) { return this.send("DELETE", path); },
};

function App() {
  const [loaded, setLoaded] = React.useState(false);
  const [view, setView] = React.useState("list");
  const [listLayout, setListLayout] = React.useState("cards");
  const [mapStyle, setMapStyle] = React.useState("satellite");
  const [dark, setDark] = React.useState(false);
  const [tweaksOpen, setTweaksOpen] = React.useState(false);
  const [parcels, setParcels] = React.useState([]);
  const [sorten, setSortenState] = React.useState([]);
  const [selected, setSelected] = React.useState(null);
  const [activeId, setActiveId] = React.useState(null);
  const [wizardOpen, setWizardOpen] = React.useState(false);
  const [editParcel, setEditParcel] = React.useState(null);

  // Keep window.SORTEN mirrored for helpers (getSorteFarbe, SortPill)
  React.useEffect(() => { window.SORTEN = sorten; }, [sorten]);
  React.useEffect(() => {
    document.documentElement.setAttribute("data-theme", dark ? "dark" : "light");
  }, [dark]);

  /* ---------- Router: Pfad ↔ State ---------- */
  // Wendet eine geparste Route auf den App-State an. Parcels müssen geladen
  // sein, damit /flaeche/:id und /flaeche/:id/bearbeiten die Parzelle finden.
  const applyRoute = React.useCallback((r, available) => {
    if (r.view === "detail" && r.selectedId) {
      const p = (available || []).find(x => x.id === r.selectedId);
      if (p) {
        setSelected(p);
        setView("list");
      } else {
        // Parzelle nicht (mehr) vorhanden → zurück zur Liste
        setSelected(null);
        setView("list");
      }
    } else {
      setSelected(null);
      setView(r.view === "detail" ? "list" : r.view);
    }
    if (r.wizardMode === "new") {
      setEditParcel(null);
      setWizardOpen(true);
    } else if (r.wizardMode === "edit" && r.selectedId) {
      const p = (available || []).find(x => x.id === r.selectedId);
      setEditParcel(p || null);
      setWizardOpen(!!p);
    } else {
      setWizardOpen(false);
      setEditParcel(null);
    }
  }, []);

  // Initial-Route anwenden, sobald Parcels geladen sind
  const initialPathRef = React.useRef(typeof window !== "undefined" ? window.location.pathname : "/");
  const initialRouteApplied = React.useRef(false);

  // popstate (Browser Zurück/Vorwärts) → State aus URL ableiten
  React.useEffect(() => {
    function onPop() {
      applyRoute(parseRoute(window.location.pathname), parcels);
    }
    window.addEventListener("popstate", onPop);
    return () => window.removeEventListener("popstate", onPop);
  }, [parcels, applyRoute]);

  // State → URL: bei jeder relevanten Änderung pushen, falls sich Pfad ändert
  React.useEffect(() => {
    if (!loaded || !initialRouteApplied.current) return;
    const wizardMode = wizardOpen ? (editParcel ? "edit" : "new") : null;
    const selectedId = selected ? selected.id : null;
    const v = selected ? "detail" : view;
    const target = buildPath(v, selectedId, wizardMode);
    if (target !== window.location.pathname) {
      window.history.pushState(null, "", target);
    }
  }, [loaded, view, selected, wizardOpen, editParcel]);

  // Initial load
  React.useEffect(() => {
    (async () => {
      try {
        const [p, s, cfg] = await Promise.all([
          api.get("/api/parcels"),
          api.get("/api/sorten"),
          api.get("/api/settings"),
        ]);
        setParcels(p);
        setSortenState(s);
        window.SORTEN = s;
        if (cfg.map_style) setMapStyle(cfg.map_style);
        if (cfg.list_layout) setListLayout(cfg.list_layout);
        if (cfg.dark_mode) setDark(cfg.dark_mode === "1");
        // Initial-Route erst anwenden, wenn Parcels bekannt sind.
        applyRoute(parseRoute(initialPathRef.current), p);
        initialRouteApplied.current = true;
      } catch (e) {
        console.error("Initial load failed", e);
        initialRouteApplied.current = true;
      } finally {
        setLoaded(true);
      }
    })();
  }, [applyRoute]);

  function persistSetting(key, value) {
    api.put("/api/settings", { [key]: value }).catch(console.error);
  }

  function setMapStyleP(v)   { setMapStyle(v);   persistSetting("map_style", v); }
  function setListLayoutP(v) { setListLayout(v); persistSetting("list_layout", v); }
  function setDarkP(v)       { setDark(v);       persistSetting("dark_mode", v ? "1" : "0"); }

  async function deleteParcel(id) {
    await api.del(`/api/parcels/${encodeURIComponent(id)}`);
    setParcels(ps => ps.filter(x => x.id !== id));
    setSelected(null);
  }

  async function saveParcel(p) {
    if (editParcel) {
      const updated = await api.put(`/api/parcels/${encodeURIComponent(p.id)}`, p);
      setParcels(ps => ps.map(x => x.id === updated.id ? updated : x));
      setSelected(updated);
    } else {
      const created = await api.post("/api/parcels", p);
      setParcels(ps => [...ps, created]);
      setSelected(created);
    }
    setWizardOpen(false);
    setEditParcel(null);
  }

  async function setSorten(next) {
    // Diff-based CRUD against the server.
    const prev = sorten;
    setSortenState(next);
    window.SORTEN = next;
    try {
      // Deletions
      for (const p of prev) {
        if (!next.find(n => n.id === p.id)) {
          if (p.id != null) await api.del(`/api/sorten/${p.id}`);
        }
      }
      // Creations + updates
      for (const n of next) {
        if (n.id == null) {
          const created = await api.post("/api/sorten", { name: n.name, farbe: n.farbe });
          // re-inject id after successful create
          setSortenState(curr => curr.map(x => x === n ? { ...x, id: created.id } : x));
        } else {
          const before = prev.find(p => p.id === n.id);
          if (before && (before.name !== n.name || before.farbe !== n.farbe)) {
            await api.put(`/api/sorten/${n.id}`, { name: n.name, farbe: n.farbe });
          }
        }
      }
    } catch (e) {
      console.error("Sorte sync failed", e);
      // Refresh from server as fallback
      const s = await api.get("/api/sorten");
      setSortenState(s);
      window.SORTEN = s;
    }
  }

  const totalHa = parcels.reduce((s, p) => s + p.flaeche, 0);

  const viewMeta = {
    list: { title: "Flächen · Übersicht", sub: `${parcels.length} Parzellen · ${fmtNum(totalHa)} ha` },
    map: { title: "Kartenansicht", sub: "Kaiserstuhl · Esri World Imagery" },
    detail: { title: selected?.lage || "Detail", sub: selected?.lagebuch || "" },
    settings: { title: "Einstellungen", sub: "Sorten · Darstellung · Standards" },
  };
  const currentView = selected ? "detail" : view;
  const meta = viewMeta[currentView];

  if (!loaded) {
    return <div style={{ padding: 40, fontFamily: "var(--font-ui)", color: "var(--ink-3)" }}>Lade Vinea…</div>;
  }

  return (
    <div className="app">
      <aside className="sidebar">
        <div className="brand">
          <div className="brand-mark">V</div>
          <div>
            <div className="brand-name">Vinea</div>
            <div className="brand-sub">Lagebuch · Kat.</div>
          </div>
        </div>
        <nav className="nav">
          <div className="nav-group-label">Verwaltung</div>
          <button className={`nav-item ${view === "list" && !selected ? "active" : ""}`} onClick={() => { setView("list"); setSelected(null); }}>
            <Icon.List /> Flächen <span className="nav-count">{parcels.length}</span>
          </button>
          <button className={`nav-item ${view === "map" && !selected ? "active" : ""}`} onClick={() => { setView("map"); setSelected(null); }}>
            <Icon.Map /> Karte
          </button>
          <button className="nav-item" onClick={() => setWizardOpen(true)}>
            <Icon.Plus /> Neue Fläche
          </button>

          <div className="nav-group-label" style={{ marginTop: 16 }}>Administration</div>
          <button
            className={`nav-item ${view === "settings" && !selected ? "active" : ""}`}
            onClick={() => { setView("settings"); setSelected(null); }}
          >
            <Icon.Settings /> Einstellungen
          </button>
        </nav>
        <div className="sidebar-footer">
          <div className="avatar">KW</div>
          <div>
            <div style={{ fontWeight: 500, color: "var(--ink-1)", fontSize: 12 }}>Weingut Kern</div>
            <div style={{ fontSize: 11 }}>Betrieb · DE-BW-1240</div>
          </div>
        </div>
      </aside>

      <div className="main">
        <header className="topbar">
          <div>
            <h1>{meta.title}</h1>
            <div className="topbar-sub">{meta.sub}</div>
          </div>
          <div className="topbar-actions">
            {currentView === "list" && (
              <div className="segmented">
                <button className={listLayout === "table" ? "active" : ""} onClick={() => setListLayoutP("table")}>
                  <Icon.List /> Tabelle
                </button>
                <button className={listLayout === "cards" ? "active" : ""} onClick={() => setListLayoutP("cards")}>
                  <Icon.Grid /> Kacheln
                </button>
              </div>
            )}
            {!selected && view !== "settings" && (
              <div className="segmented">
                <button className={view === "list" ? "active" : ""} onClick={() => setView("list")}>Liste</button>
                <button className={view === "map" ? "active" : ""} onClick={() => setView("map")}>Karte</button>
              </div>
            )}
            {view !== "settings" && (
              <button className="btn btn-primary" onClick={() => setWizardOpen(true)}>
                <Icon.Plus /> Neue Fläche
              </button>
            )}
          </div>
        </header>

        <main className="content">
          {selected ? (
            <DetailView parcel={selected} onBack={() => setSelected(null)} onEdit={() => { setEditParcel(selected); setWizardOpen(true); }} mapStyle={mapStyle} />
          ) : view === "settings" ? (
            <SettingsView
              sorten={sorten}
              setSorten={setSorten}
              mapStyle={mapStyle}
              setMapStyle={setMapStyleP}
              listLayout={listLayout}
              setListLayout={setListLayoutP}
              persistTweak={(k, v) => persistSetting(k === "mapStyle" ? "map_style" : k === "listLayout" ? "list_layout" : k, v)}
            />
          ) : view === "list" ? (
            <ListView
              parcels={parcels}
              onSelect={setSelected}
              onNew={() => setWizardOpen(true)}
              layout={listLayout}
              setLayout={setListLayoutP}
              mapStyle={mapStyle}
            />
          ) : (
            <MapView
              parcels={parcels}
              onSelect={setSelected}
              activeId={activeId}
              setActiveId={setActiveId}
              mapStyle={mapStyle}
            />
          )}
        </main>
      </div>

      {/* Mobile bottom navigation */}
      <nav className="bottom-nav">
        <button
          className={`bottom-nav-item ${view === "list" && !selected ? "active" : ""}`}
          onClick={() => { setView("list"); setSelected(null); }}
        >
          <Icon.List />
          <span>Flächen</span>
        </button>
        <button
          className={`bottom-nav-item ${view === "map" && !selected ? "active" : ""}`}
          onClick={() => { setView("map"); setSelected(null); }}
        >
          <Icon.Map />
          <span>Karte</span>
        </button>
        <button
          className="bottom-nav-item bottom-nav-new"
          onClick={() => setWizardOpen(true)}
        >
          <Icon.Plus />
          <span>Neu</span>
        </button>
        <button
          className={`bottom-nav-item ${view === "settings" && !selected ? "active" : ""}`}
          onClick={() => { setView("settings"); setSelected(null); }}
        >
          <Icon.Settings />
          <span>Einstellungen</span>
        </button>
      </nav>

      {wizardOpen && (
        <Wizard
          onClose={() => { setWizardOpen(false); setEditParcel(null); }}
          onDelete={async (id) => { await deleteParcel(id); setWizardOpen(false); setEditParcel(null); }}
          existingParcels={parcels}
          editParcel={editParcel}
          mapStyle={mapStyle}
          onSave={saveParcel}
        />
      )}

      <div className={`tweaks ${tweaksOpen ? "open" : ""}`}>
        <h4>
          Tweaks
          <button className="modal-close" onClick={() => setTweaksOpen(false)}><Icon.X /></button>
        </h4>
        <div className="tweak-row">
          <span>Kartenstil</span>
          <div className="segmented" style={{ padding: 2 }}>
            <button className={mapStyle === "satellite" ? "active" : ""} onClick={() => setMapStyleP("satellite")}>Satellit</button>
            <button className={mapStyle === "illustrated" ? "active" : ""} onClick={() => setMapStyleP("illustrated")}>Illustriert</button>
          </div>
        </div>
        <div className="tweak-row">
          <span>Listen-Layout</span>
          <div className="segmented" style={{ padding: 2 }}>
            <button className={listLayout === "table" ? "active" : ""} onClick={() => setListLayoutP("table")}>Tabelle</button>
            <button className={listLayout === "cards" ? "active" : ""} onClick={() => setListLayoutP("cards")}>Kacheln</button>
          </div>
        </div>
        <div className="tweak-row">
          <span>Dark Mode</span>
          <div className={`toggle ${dark ? "on" : ""}`} onClick={() => setDarkP(!dark)} />
        </div>
      </div>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
