/* app.jsx — application shell wired to the live backend (window.API). */
const { useState, useMemo, useEffect, useCallback } = React;

const NAV = [
  { group: "Overview", items: [{ id: "dashboard", label: "Dashboard", icon: "dashboard" }] },
  { group: "Operations", items: [
    { id: "projects", label: "Projects", icon: "projects" },
    { id: "customers", label: "Customers", icon: "customers" },
    { id: "email", label: "Email", icon: "mail" },
  ] },
  { group: "Finance", items: [
    { id: "invoices", label: "Invoices", icon: "invoices" },
    { id: "expenses", label: "Expenses", icon: "expenses" },
    { id: "payments", label: "Payments", icon: "wallet" },
    { id: "employees", label: "Employees", icon: "employees" },
  ] },
];

const VIEW_META = {
  dashboard: ["Dashboard", "Cashflow, receivables & operating movement"],
  projects: ["Projects", "Project records, deliverables & linked customers"],
  customers: ["Customers", "Billing details, notes & correspondence"],
  email: ["Email", "Inbox, message details & replies"],
  invoices: ["Invoices", "Drafts, finalization & payments"],
  expenses: ["Expenses", "Operating spend, wages & recurring costs"],
  payments: ["Payments", "Outgoing expense payment queue"],
  employees: ["Employees", "Staff records & payroll"],
  settings: ["Settings", "Company profile & billing defaults"],
};

function milestoneInvoiceAmount(milestone) {
  return (Number(milestone.actualCost) || 0)
    || ((Number(milestone.actualHours) || 0) * (Number(milestone.hourlyRate) || 0))
    || ((Number(milestone.estimatedHours) || 0) * (Number(milestone.hourlyRate) || 0));
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "sidebar": "dark",
  "accent": "#2856c4",
  "density": "regular"
}/*EDITMODE-END*/;

function viewFromHash() {
  const view = window.location.hash.replace(/^#\/?/, "").split("/")[0];
  return VIEW_META[view] ? view : "dashboard";
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [db, setDb] = useState(null);
  const [session, setSession] = useState(null);
  const [authLoading, setAuthLoading] = useState(true);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [view, setViewState] = useState(viewFromHash);
  const [year, setYear] = useState(new Date().getFullYear());
  const [query, setQuery] = useState("");
  const [drawer, setDrawer] = useState(null);
  const [toast, setToast] = useState(null);
  const [unreadInboxCount, setUnreadInboxCount] = useState(0);

  const reload = useCallback(async () => {
    try { const next = await window.API.loadDb(); setDb(next); setError(null); }
    catch (e) {
      if (e.status === 401) {
        setSession({ authenticated: false, user: null });
        setDb(null);
        setError(null);
      } else {
        setError(e.message || "Failed to load data.");
      }
    }
    finally { setLoading(false); }
  }, []);

  const refreshSession = useCallback(async () => {
    try { setSession(await window.API.session()); setError(null); }
    catch (e) { setError(e.message || "Failed to load session."); }
    finally { setAuthLoading(false); }
  }, []);

  useEffect(() => { refreshSession(); }, [refreshSession]);
  useEffect(() => {
    if (!session) return;
    if (session.authenticated) {
      setLoading(true);
      reload();
    } else {
      setDb(null);
      setLoading(false);
    }
  }, [session, reload]);
  useEffect(() => {
    if (!session || !session.authenticated || !window.API.subscribeToChanges) return;
    let timer = null;
    const unsubscribe = window.API.subscribeToChanges(() => {
      if (timer) clearTimeout(timer);
      timer = setTimeout(() => {
        timer = null;
        reload();
      }, 100);
    });
    return () => {
      if (timer) clearTimeout(timer);
      unsubscribe();
    };
  }, [session, reload]);
  useEffect(() => {
    const syncView = () => setViewState(viewFromHash());
    window.addEventListener("hashchange", syncView);
    return () => window.removeEventListener("hashchange", syncView);
  }, []);

  useEffect(() => {
    document.documentElement.style.setProperty("--primary", t.accent);
    document.documentElement.style.setProperty("--primary-strong", shade(t.accent, -18));
    document.documentElement.style.setProperty("--primary-soft", tint(t.accent, 0.9));
    document.documentElement.style.setProperty("--primary-tint", tint(t.accent, 0.955));
  }, [t.accent]);
  useEffect(() => { if (!toast) return; const id = setTimeout(() => setToast(null), 2200); return () => clearTimeout(id); }, [toast]);
  useEffect(() => { setQuery(""); }, [view]);

  const setView = useCallback((nextView) => {
    setViewState(nextView);
    const nextHash = nextView === "dashboard" ? "" : `#${nextView}`;
    if (window.location.hash !== nextHash) {
      window.history.pushState(null, "", `${window.location.pathname}${window.location.search}${nextHash}`);
      window.dispatchEvent(new Event("hashchange"));
    }
  }, []);

  const flash = (msg) => setToast(msg);
  const fail = (e) => setError((e && e.message) || "Request failed.");
  const openDrawer = (type, editId, context = {}) => setDrawer({ type, editId, context });
  const closeDrawer = () => setDrawer(null);

  const overdueCount = useMemo(() => db ? db.invoices.filter((iv) => MODEL.enrich(db, iv).overdue).length : 0, [db]);

  const refreshUnreadInboxCount = useCallback(async () => {
    if (!db || !db.settings || !db.settings.emailEnabled || !db.settings.emailPassword) {
      setUnreadInboxCount(0);
      return;
    }

    try {
      const result = await window.API.getEmailUnreadCount();
      setUnreadInboxCount(Number(result.count) || 0);
    } catch (_) {
      setUnreadInboxCount(0);
    }
  }, [db]);

  useEffect(() => { refreshUnreadInboxCount(); }, [refreshUnreadInboxCount]);

  async function handleInvoiceAction(action, iv) {
    try {
      if (action === "print") { window.open(`/invoices/${iv.id}/print`, "_blank", "noreferrer"); return true; }
      if (action === "download") { window.open(`/invoices/${iv.id}/download`, "_blank"); return true; }
      if (action === "downloadProjectOffer") { window.open(`/projects/${iv.projectId}/offers/${iv.id}/download`, "_blank"); return true; }
      if (action === "doc") { window.open(`/api/expenses/${iv.id}/document`, "_blank", "noreferrer"); return true; }
      if (action === "openProjectDocument") { window.open(`/api/projects/${iv.projectId}/documents/${iv.documentId}`, "_blank", "noreferrer"); return true; }
      if (action === "uploadProjectDocument") {
        await window.API.uploadProjectDocument(iv.projectId, iv.file, iv);
        flash("Project document uploaded");
      }
      if (action === "deleteProjectDocument") {
        if (!window.confirm(`Remove ${iv.fileName}?`)) return;
        await window.API.deleteProjectDocument(iv.projectId, iv.documentId);
        flash("Project document removed");
      }
      if (action === "updateProjectPlanning") {
        await window.API.updateProjectPlanning(iv.projectId, iv);
        flash("Project planning updated");
      }
      if (action === "updateProject") {
        await window.API.updateProject(iv.projectId, { ...iv.project, ...iv.patch });
        flash("Project updated");
      }
      if (action === "toggleProjectMilestone") {
        const milestone = (iv.project.milestones || []).find((item) => item.id === iv.milestoneId);
        if (!milestone) return false;
        await window.API.updateProjectMilestone(iv.project.id, milestone.id, { ...milestone, completed: !milestone.completed });
        flash("Milestone updated");
      }
      if (action === "reorderProjectMilestone") {
        const allMilestones = iv.project.milestones || [];
        const current = allMilestones.find((item) => item.id === iv.milestoneId);
        if (!current) return false;
        const milestones = allMilestones.filter((item) => item.planningSectionId === current.planningSectionId);
        const from = milestones.findIndex((item) => item.id === iv.milestoneId);
        const to = from + iv.direction;
        if (from < 0 || to < 0 || to >= milestones.length) return false;
        const ordered = milestones.map((item) => item.id);
        [ordered[from], ordered[to]] = [ordered[to], ordered[from]];
        await window.API.reorderProjectMilestones(iv.project.id, ordered);
        flash("Milestones reordered");
      }
      if (action === "createMilestoneDeliverables") {
        for (const milestone of iv.milestones || []) {
          const unitPrice = milestoneInvoiceAmount(milestone);
          await window.API.createProjectDeliverable(iv.project.id, {
            projectId: iv.project.id,
            billingStartDate: milestone.dueDate || window.AC.TODAY,
            milestoneIds: [milestone.id],
            name: milestone.title,
            kind: "Milestone",
            status: "Active",
            description: milestone.dueDate ? `Due ${milestone.dueDate}` : "",
            unitPrice,
            taxRate: 0.19,
            freeOfCharge: unitPrice <= 0,
            recurrenceFrequency: "None",
            recurrenceEndDate: "",
            customFields: {},
          });
        }
        flash(`${(iv.milestones || []).length} deliverable${(iv.milestones || []).length !== 1 ? 's' : ''} created`);
      }
      if (action === "removeDoc") {
        if (!window.confirm("Remove this document from the expense?")) return;
        await window.API.deleteExpenseDocument(iv.id);
        flash("Expense document removed");
      }
      if (action === "deleteExpense") {
        if (!window.confirm(`Delete ${iv.category} expense?`)) return;
        await window.API.deleteExpense(iv.id);
        flash("Expense deleted");
      }
      if (action === "payExpenseOccurrence") {
        await window.API.payExpenseOccurrence(iv.expense.id, iv.occurrenceDate);
        flash("Expense payment recorded");
      }
      if (action === "finalize") { await window.API.finalizeInvoice(iv.id); flash(`${iv.number} finalized`); }
      if (action === "pay") { await window.API.payInvoice(iv.id, MODEL.totals(iv).outstanding); flash(`${iv.number} marked paid`); }
      if (action === "cancel") { await window.API.cancelInvoice(iv.id); flash(`${iv.number} cancelled`); }
      if (action === "delete") {
        if (!window.confirm(`Delete ${iv.number}?`)) return;
        await window.API.deleteInvoice(iv.id);
        flash(`${iv.number} deleted`);
      }
      if (action === "deleteProjectDeliverable") {
        if (!window.confirm(`Delete ${iv.name}?`)) return;
        await window.API.deleteProjectDeliverable(iv.projectId, iv.id);
        flash("Deliverable deleted");
      }
      if (action === "unlinkProjectCustomer") {
        if (!window.confirm(`Remove ${iv.customerName} from this project?`)) return;
        await window.API.unlinkProjectCustomer(iv.projectId, iv.customerId);
        flash("Customer removed from project");
      }
      if (action === "deleteCustomerContact") {
        if (!window.confirm(`Remove ${iv.contactName}?`)) return;
        await window.API.deleteCustomerContact(iv.customerId, iv.contactId);
        flash("Contact removed");
      }
      if (action === "deleteCorrespondence") {
        if (!window.confirm(`Delete ${iv.subject || 'this correspondence'}?`)) return;
        await window.API.deleteCustomerCorrespondence(iv.customerId, iv.id);
        flash("Correspondence deleted");
      }
      if (action === "deleteProjectMilestone") {
        if (!window.confirm(`Delete ${iv.title}?`)) return;
        await window.API.deleteProjectMilestone(iv.projectId, iv.id);
        flash("Milestone deleted");
      }
      if (action === "deleteProject") {
        if (!window.confirm(`Delete ${iv.name}? Draft invoices for this project will also be removed.`)) return;
        await window.API.deleteProject(iv.id);
        flash("Project deleted");
      }
      if (action === "deleteProjectOffer") {
        if (!window.confirm(`Delete ${iv.title}?`)) return;
        await window.API.deleteProjectOffer(iv.projectId, iv.id);
        flash("Offer deleted");
      }
      if (action === "convertProjectOffer") {
        if (!window.confirm(`Convert ${iv.title} to project deliverable${(iv.lines || []).length !== 1 ? 's' : ''}?`)) return;
        await window.API.convertProjectOffer(iv.projectId, iv.id);
        flash("Offer converted");
      }
      await reload();
      return true;
    } catch (e) { fail(e); return false; }
  }

  async function handleSubmit(type, f, editId) {
    try {
      if (type === "invoice") {
        editId ? await window.API.updateInvoice(editId, f) : await window.API.createInvoice(f);
        flash(editId ? "Invoice updated" : "Draft invoice created");
      } else if (type === "expense") {
        const saved = editId ? await window.API.updateExpense(editId, f) : await window.API.createExpense(f);
        const file = document.querySelector('.drawer input[type=file]');
        if (file && file.files && file.files[0]) await window.API.uploadExpenseDocument(saved.id, file.files[0]);
        flash(editId ? "Expense updated" : "Expense recorded");
      } else if (type === "customer") {
        editId ? await window.API.updateCustomer(editId, f) : await window.API.createCustomer(f);
        flash(editId ? "Customer updated" : "Customer added");
      } else if (type === "project") {
        if (editId) {
          const existing = db.projects.find((p) => p.id === editId);
          await window.API.updateProject(editId, { ...existing, ...f, customFields: existing.customFields || {}, customerIds: existing.customerIds || [] });
          flash("Project updated");
        } else {
          await window.API.createProject({ ...f, customFields: {}, customerIds: f.customerId ? [f.customerId] : [] });
          flash("Project created");
        }
      } else if (type === "projectCustomer") {
        await window.API.linkProjectCustomer(f.projectId, f.customerId);
        flash("Customer linked");
      } else if (type === "projectMilestone") {
        if (editId) {
          const project = db.projects.find((item) => item.id === f.projectId);
          const existing = project && (project.milestones || []).find((item) => item.id === editId);
          const onlyEffortChanged = existing
            && (existing.title || '') === (f.title || '')
            && (existing.dueDate || '') === (f.dueDate || '')
            && !!existing.completed === !!f.completed;
          onlyEffortChanged
            ? await window.API.updateProjectMilestoneEffort(f.projectId, editId, f)
            : await window.API.updateProjectMilestone(f.projectId, editId, f);
        } else {
          await window.API.createProjectMilestone(f.projectId, f);
        }
        flash(editId ? "Milestone updated" : "Milestone created");
      } else if (type === "projectDeliverable") {
        editId ? await window.API.updateProjectDeliverable(f.projectId, editId, f) : await window.API.createProjectDeliverable(f.projectId, f);
        flash(editId ? "Deliverable updated" : "Deliverable created");
      } else if (type === "deliverableInvoice") {
        const invoices = await window.API.createProjectDeliverableInvoices(f.projectId, f.deliverableId, f);
        flash(invoices.length ? `${invoices.length} invoice draft${invoices.length !== 1 ? 's' : ''} created` : "No missing invoices");
      } else if (type === "projectOffer") {
        editId ? await window.API.updateProjectOffer(f.projectId, editId, f) : await window.API.createProjectOffer(f.projectId, f);
        flash(editId ? "Offer updated" : "Offer created");
      } else if (type === "employee") {
        editId ? await window.API.updateEmployee(editId, f) : await window.API.createEmployee(f);
        flash(editId ? "Employee updated" : "Employee added");
      } else if (type === "correspondence") {
        if (editId) {
          await window.API.updateCustomerCorrespondence(f.customerId, editId, f);
        } else if (f.projectId && !f.customerId) {
          await window.API.createProjectCorrespondence(f.projectId, f);
        } else {
          await window.API.createCustomerCorrespondence(f.customerId, f);
        }
        flash(editId ? "Correspondence updated" : "Correspondence added");
      } else if (type === "customerContact") {
        editId
          ? await window.API.updateCustomerContact(f.customerId, editId, f)
          : await window.API.createCustomerContact(f.customerId, f);
        flash(editId ? "Contact updated" : "Contact added");
      }
      closeDrawer();
      await reload();
    } catch (e) { fail(e); }
  }

  async function handleSettings(next) {
    try { await window.API.updateSettings({ ...next, nextInvoiceNumber: parseInt(next.nextInvoiceNumber || "1", 10) || 1 }); flash("Settings saved"); await reload(); }
    catch (e) { fail(e); }
  }

  async function handleAuth(form) {
    try {
      const next = await window.API.login(form);
      setSession(next);
      setError(null);
    } catch (e) { fail(e); }
  }

  async function handleLogout() {
    try {
      await window.API.logout();
      setSession({ authenticated: false, user: null });
      setDb(null);
      flash("Signed out");
    } catch (e) { fail(e); }
  }

  if (authLoading || (session && session.authenticated && loading)) return <div className="boot"><div className="boot-mark">A</div><span>Loading workspace…</span></div>;
  if (session && !session.authenticated) return <LandingPage error={error} onSubmit={handleAuth} />;
  if (!db) return <div className="boot"><div className="alert" style={{ maxWidth: 420 }}>{error || "No data."}</div><button className="btn" onClick={reload}>Retry</button></div>;

  const meta = VIEW_META[view];
  const section = (NAV.find((g) => g.items.some((i) => i.id === view)) || { group: "Workspace" }).group;
  const screenProps = { db, query, onDrawer: openDrawer, onAction: handleInvoiceAction, onNav: setView, onToast: flash, onError: fail, onReload: reload, onUnreadRefresh: refreshUnreadInboxCount };
  const currentUser = session && session.user;

  return (
    <div className="app" data-sidebar={t.sidebar} data-density={t.density}>
      <aside className="sidebar">
        <div className="brand">
          <span className="mark">A</span>
          <div><strong>{db.settings.companyName}</strong><small>Operations</small></div>
        </div>
        {NAV.map((g) => (
          <div className="nav-group" key={g.group}>
            <div className="nav-label">{g.group}</div>
            {g.items.map((it) => (
              <button key={it.id} className={`nav-btn ${view === it.id ? "active" : ""}`} onClick={() => setView(it.id)}>
                <Icon name={it.icon} size={15} className="ico" />
                <span className="label">{it.label}</span>
                {it.id === "email" && unreadInboxCount > 0 && <span className="unread-dot" title={`${unreadInboxCount} unread inbox email${unreadInboxCount === 1 ? "" : "s"}`} />}
                {it.id === "invoices" && overdueCount > 0 && <span className="badge">{overdueCount}</span>}
              </button>
            ))}
          </div>
        ))}
        <div className="nav-group">
          <button className={`nav-btn ${view === "settings" ? "active" : ""}`} onClick={() => setView("settings")}>
            <Icon name="settings" size={15} className="ico" /><span className="label">Settings</span>
          </button>
        </div>
        <div className="sb-foot">
          <div className="who">
            <span className="avatar">{((currentUser && currentUser.name) || db.settings.companyName || "A").slice(0, 2).toUpperCase()}</span>
            <div className="meta"><div style={{ color: "var(--sb-text-strong)", fontWeight: 600, fontSize: 12 }}>{(currentUser && currentUser.name) || db.settings.companyName}</div><div style={{ fontSize: 10.5 }}>{currentUser ? currentUser.role : "Operations"}</div></div>
          </div>
        </div>
      </aside>

      <main className="main">
        <header className="topbar">
          <div>
            <div className="crumb">{view === "settings" ? "Settings" : section}</div>
            <h1>{meta[0]}</h1>
          </div>
          <div className="spacer" />
          {["invoices", "expenses", "payments", "customers", "projects", "employees", "email"].includes(view) &&
            <SearchBox value={query} onChange={setQuery} placeholder={`Search ${view}…`} />}
          <button className="icon-btn" title="Refresh" onClick={() => { setLoading(true); reload().then(() => flash("Data refreshed")); }}><Icon name="refresh" size={16} /></button>
          <button className="icon-btn" title="Sign out" onClick={handleLogout}><Icon name="logout" size={16} /></button>
        </header>

        {error && <div className="alert" style={{ margin: "12px 20px 0" }}>{error}</div>}

        <div className="content">
          {view === "dashboard" && <Dashboard db={db} year={year} setYear={setYear} onNav={setView} />}
          {view === "projects" && <Projects {...screenProps} />}
          {view === "customers" && <Customers {...screenProps} />}
          {view === "email" && <Email {...screenProps} />}
          {view === "invoices" && <Invoices {...screenProps} />}
          {view === "expenses" && <Expenses {...screenProps} />}
          {view === "payments" && <Payments {...screenProps} />}
          {view === "employees" && <Employees {...screenProps} />}
          {view === "settings" && <Settings db={db} session={session} onToast={flash} onError={fail} onSave={handleSettings} />}
        </div>
      </main>

      {drawer && <Drawer type={drawer.type} editId={drawer.editId} context={drawer.context} db={db} onClose={closeDrawer} onSubmit={handleSubmit} onAction={handleInvoiceAction} />}
      {toast && <div className="toast"><Icon name="check" size={14} style={{ verticalAlign: "-2px", marginRight: 6 }} />{toast}</div>}

      <TweaksPanel>
        <TweakSection label="Navigation" />
        <TweakRadio label="Sidebar" value={t.sidebar} options={[{ value: "dark", label: "Dark" }, { value: "light", label: "Light" }, { value: "compact", label: "Icons" }]} onChange={(v) => setTweak("sidebar", v)} />
        <TweakSection label="Appearance" />
        <TweakColor label="Accent" value={t.accent} options={["#2856c4", "#0e7490", "#3f3f9e", "#15803d", "#1e293b"]} onChange={(v) => setTweak("accent", v)} />
        <TweakRadio label="Row density" value={t.density} options={[{ value: "compact", label: "Compact" }, { value: "regular", label: "Regular" }, { value: "comfortable", label: "Comfy" }]} onChange={(v) => setTweak("density", v)} />
      </TweaksPanel>
    </div>
  );
}

function BrandMark() {
  return <img src="/assets/appligator-icon.png" alt="" aria-hidden="true" />;
}

function LandingPage({ error, onSubmit }) {
  const [loginOpen, setLoginOpen] = React.useState(!!error);
  const openLogin = React.useCallback(() => setLoginOpen(true), []);
  const closeLogin = React.useCallback(() => setLoginOpen(false), []);
  useReveal();

  React.useEffect(() => {
    if (error) setLoginOpen(true);
  }, [error]);

  return (
    <div className="lp" data-accent="green" data-paper="warm">
      <LandingNav onLogin={openLogin} />
      <Hero />
      <Pipeline />
      <Services />
      <LeanDelivery />
      <TrustStrip />
      <LandingCTA onLogin={openLogin} />
      <LandingFooter />
      <LoginModal open={loginOpen} error={error} onClose={closeLogin} onSubmit={onSubmit} />
    </div>
  );
}

function LandingLogo() {
  return <span className="mark"><BrandMark /></span>;
}

function LandingIcon({ name, size = 20, stroke = 1.7, style }) {
  return <Icon name={name} size={size} stroke={stroke} style={style} />;
}

function useReveal() {
  React.useEffect(() => {
    const els = Array.from(document.querySelectorAll(".lp .reveal"));
    let raf = 0;
    const check = () => {
      raf = 0;
      const trigger = window.innerHeight * 0.92;
      for (let i = els.length - 1; i >= 0; i--) {
        const el = els[i];
        if (el.getBoundingClientRect().top < trigger) {
          el.classList.add("in");
          els.splice(i, 1);
        }
      }
      if (!els.length) {
        window.removeEventListener("scroll", onScroll);
        window.removeEventListener("resize", onScroll);
      }
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(check); };
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    check();
    const safety = setTimeout(() => els.slice().forEach((el) => el.classList.add("in")), 1600);
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      if (raf) cancelAnimationFrame(raf);
      clearTimeout(safety);
    };
  }, []);
}

function LandingNav({ onLogin }) {
  const [scrolled, setScrolled] = React.useState(false);
  React.useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 8);
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  return (
    <header className={"lp-nav" + (scrolled ? " scrolled" : "")}>
      <div className="row">
        <a className="brand" href="#top" aria-label="Appligator home">
          <LandingLogo />
          <span style={{ display: "inline-flex", alignItems: "center" }}>Appligator<span className="tag">Impl</span></span>
        </a>
        <nav aria-label="Company">
          <a href="#process">Process</a>
          <a href="#services">Services</a>
          <a href="#delivery">Why lean</a>
          <a href="#hosting">Hosting</a>
        </nav>
        <div className="nav-actions">
          <button className="btn subtle" type="button" onClick={onLogin}>Internal log in</button>
          <a className="btn sm" href="#contact">Start a project <LandingIcon name="arrow" size={16} /></a>
        </div>
      </div>
    </header>
  );
}

function Hero() {
  return (
    <section className="hero" id="top">
      <div className="shell hero-grid">
        <div className="hero-copy">
          <span className="kicker reveal">Software implementation · small & medium projects</span>
          <h1 className="reveal d1">From first idea to <span className="accent">finished software</span>—on one lean line.</h1>
          <p className="lede reveal d1">
            Appligator turns a new project idea into a clear plan, a small useful core, and
            software your team can run, own, and keep improving. No enterprise drag. No detours.
          </p>
          <div className="hero-actions reveal d2">
            <a className="btn lg" href="#contact">Start a project <LandingIcon name="arrow" size={17} /></a>
            <a className="btn ghost lg" href="#process">See how we work</a>
          </div>
          <div className="hero-trust reveal d2">
            <span><span className="dot" /> Fixed, visible scope</span>
            <span><span className="dot" /> Built to hand over</span>
            <span><span className="dot" /> Hosting optional</span>
          </div>
        </div>
        <ProductPeek />
      </div>
    </section>
  );
}

function ProductPeek() {
  return (
    <div className="peek-wrap reveal d2">
      <div className="peek">
        <div className="peek-bar">
          <span className="dots"><i></i><i></i><i></i></span>
          <span className="url"><LandingIcon name="shield" size={11} /> app.appligator.dev/projects</span>
        </div>
        <div className="peek-body">
          <div className="peek-row">
            <div>
              <div className="peek-title">Orchard — inventory</div>
              <div className="peek-sub">Week 03 / 05 · on plan</div>
            </div>
            <span className="peek-pill"><span className="pdot"></span> In delivery</span>
          </div>
          <div className="peek-board">
            <div className="peek-col">
              <h5>Scope <b>done</b></h5>
              <div className="peek-card done"><span className="cl"><span>Workflow</span></span></div>
              <div className="peek-card done"><span className="cl"><span>Data model</span></span></div>
            </div>
            <div className="peek-col">
              <h5>Build <b>now</b></h5>
              <div className="peek-card"><span className="cl"><span>Core UI</span></span><div className="bar"><i style={{ width: "72%" }}></i></div></div>
              <div className="peek-card"><span className="cl"><span>API wiring</span></span><div className="bar"><i style={{ width: "40%" }}></i></div></div>
            </div>
            <div className="peek-col">
              <h5>Launch <b>next</b></h5>
              <div className="peek-card"><span className="cl"><span>Hosting</span></span></div>
            </div>
          </div>
          <div className="peek-meter">
            <span className="peek-sub" style={{ textTransform: "none", letterSpacing: 0 }}>Delivery</span>
            <span className="track"><i style={{ width: "64%" }}></i></span>
            <b>64%</b>
          </div>
        </div>
      </div>
      <div className="peek-float">
        <span className="pf-ic"><LandingIcon name="handover" size={16} /></span>
        <span className="pf-txt">
          <span className="pf-k">Handover</span>
          <span className="pf-v">You own the code</span>
        </span>
      </div>
    </div>
  );
}

const LANDING_STEPS = [
  ["01", "Idea", "We map the real workflow, the inputs, and what success looks like.", "Day 1-3"],
  ["02", "Plan", "A compact scope with visible milestones — no surprises, no bloat.", "Week 1"],
  ["03", "Build", "The useful core first, reviewed with you as it takes shape.", "Week 2-4"],
  ["04", "Launch", "Hosted, handed over, and documented. The code is yours.", "Week 5"],
];

function Pipeline() {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let raf = 0;
    let done = false;
    const check = () => {
      raf = 0;
      if (done) return;
      if (el.getBoundingClientRect().top < window.innerHeight * 0.78) {
        el.classList.add("lit");
        done = true;
        window.removeEventListener("scroll", onScroll);
      }
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(check); };
    window.addEventListener("scroll", onScroll, { passive: true });
    check();
    const safety = setTimeout(() => el.classList.add("lit"), 2000);
    return () => {
      window.removeEventListener("scroll", onScroll);
      if (raf) cancelAnimationFrame(raf);
      clearTimeout(safety);
    };
  }, []);

  return (
    <section className="pipeline-section" id="process">
      <div className="shell">
        <div className="pipeline-head">
          <div>
            <span className="kicker reveal">The lean line</span>
            <h2 className="reveal d1">Four steps. One direction. Idea to release in weeks, not quarters.</h2>
          </div>
          <p className="pl-note reveal d2">Every project follows the same slim path — so progress, decisions, and handover stay easy to see at any point.</p>
        </div>
        <div className="pipeline" ref={ref}>
          <span className="pl-progress"></span>
          {LANDING_STEPS.map(([n, title, body, week]) => (
            <div className="pl-node reveal" key={n}>
              <span className="pl-dot">{n}</span>
              <div className="pl-body">
                <span className="pl-week">{week}</span>
                <h3>{title}</h3>
                <p>{body}</p>
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

const LANDING_SERVICES = [
  ["projects", "Project implementation", "Custom workflows, dashboards, integrations, automations, and client portals built around one concrete business need."],
  ["handover", "Operational handover", "You keep the code in your own repositories, cloud accounts, and delivery process. No lock-in, ever."],
  ["server", "Managed hosting", "Prefer a single point of responsibility? Appligator can run hosting, monitoring, and updates for you."],
];

function Services() {
  return (
    <section className="section alt" id="services">
      <div className="shell">
        <div className="section-head">
          <span className="kicker reveal">What we do</span>
          <h2 className="reveal d1">From scope to shipped software—without turning every request into a programme.</h2>
        </div>
        <div className="services">
          {LANDING_SERVICES.map(([icon, title, body], i) => (
            <article className={"svc reveal d" + i} key={title} id={icon === "server" ? "hosting" : undefined}>
              <span className="svc-num mono">0{i + 1}</span>
              <span className="ic"><LandingIcon name={icon} size={22} /></span>
              <h3>{title}</h3>
              <p>{body}</p>
            </article>
          ))}
        </div>
      </div>
    </section>
  );
}

const LANDING_POINTS = [
  ["Compact scope, sharp focus", "We solve the agreed workflow first, then grow only where the business case is clear."],
  ["Visible milestones", "Direct feedback loops and weekly checkpoints keep delivery honest and predictable."],
  ["Built to be owned", "Clean, documented code you can keep, extend, or take in-house at any time."],
];

function LeanDelivery() {
  return (
    <section className="section" id="delivery">
      <div className="shell lean">
        <div className="lean-copy">
          <span className="kicker reveal">Delivery model</span>
          <h2 className="reveal d1">Small enough to stay sharp. Structured enough to rely on.</h2>
          <p className="reveal d1">
            Big programmes lose momentum in process. We keep teams small, scopes tight, and the
            line to launch short — so the software solving your workflow ships while it still matters.
          </p>
          <span className="own-chip reveal d2"><LandingIcon name="check" size={16} /> Your repositories. Your cloud. Your code.</span>
        </div>
        <div className="lean-points">
          {LANDING_POINTS.map(([heading, body], i) => (
            <div className={"lp-point reveal d" + i} key={heading}>
              <span className="n">{String(i + 1).padStart(2, "0")}</span>
              <div>
                <h4>{heading}</h4>
                <p>{body}</p>
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

const LANDING_STATS = [
  ["5", "weeks", "Typical idea-to-launch for a useful first version"],
  ["1", "team", "Small, senior, end-to-end — no handoffs between silos"],
  ["100%", "", "Of the code handed over and owned by the client"],
  ["0", "lock-in", "Self-host, switch, or take it in-house whenever you like"],
];

function TrustStrip() {
  return (
    <section className="section alt">
      <div className="shell">
        <div className="trust reveal">
          {LANDING_STATS.map(([value, unit, caption]) => (
            <div className="ts" key={caption}>
              <div className="v"><b>{value}</b>{unit && <span style={{ fontSize: ".5em", color: "var(--muted)", marginLeft: 4 }}>{unit}</span>}</div>
              <div className="k">{caption}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

function LandingCTA({ onLogin }) {
  return (
    <section className="cta-wrap" id="contact">
      <div className="shell">
        <div className="cta reveal">
          <div className="cta-copy">
            <span className="kicker">Start a project</span>
            <h2>Have an idea worth shipping? Let's map the lean line to launch.</h2>
            <p>Tell us the workflow you want to fix. We'll come back with a compact scope, a timeline, and a fixed first milestone—usually within a couple of days.</p>
          </div>
          <div className="cta-actions">
            <a className="btn lg" href="mailto:info@appligator.de">Book a scoping call <LandingIcon name="arrow" size={17} /></a>
            <button className="btn ghost lg" type="button" onClick={onLogin}>Internal log in</button>
          </div>
        </div>
      </div>
    </section>
  );
}

function LandingFooter() {
  return (
    <footer className="lp-foot">
      <div className="shell">
        <div className="row">
          <div>
            <a className="brand" href="#top"><LandingLogo /><span>Appligator</span></a>
            <p className="f-blurb">Software implementation for small and medium-sized projects. From first idea to finished, owned software—on one lean line.</p>
          </div>
          <div className="f-cols">
            <div className="f-col">
              <h5>Company</h5>
              <a href="#process">Process</a>
              <a href="#services">Services</a>
              <a href="#delivery">Why lean</a>
              <a href="#hosting">Hosting</a>
            </div>
            <div className="f-col">
              <h5>Get in touch</h5>
              <a href="mailto:info@appligator.de">info@appligator.de</a>
              <a href="#contact">Start a project</a>
            </div>
          </div>
        </div>
        <div className="f-base">
          <span className="mono">© {new Date().getFullYear()} Appligator Company</span>
          <span className="mono">01000001 · idea → release</span>
        </div>
      </div>
    </footer>
  );
}

function LoginModal({ open, error, onClose, onSubmit }) {
  const [form, setForm] = React.useState({ email: "", password: "" });
  const [busy, setBusy] = React.useState(false);
  const set = (key, value) => setForm((current) => ({ ...current, [key]: value }));

  React.useEffect(() => {
    if (!open) return;
    const onKey = (event) => { if (event.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => {
      window.removeEventListener("keydown", onKey);
      document.body.style.overflow = "";
    };
  }, [open, onClose]);

  const submit = async (event) => {
    event.preventDefault();
    setBusy(true);
    try { await onSubmit(form); }
    finally { setBusy(false); }
  };

  if (!open) return null;
  return (
    <div className="login-overlay" onMouseDown={(event) => { if (event.target === event.currentTarget) onClose(); }}>
      <form className="login-card" onSubmit={submit}>
        <div className="lc-head">
          <span className="mark"><BrandMark /></span>
          <div><strong>Appligator Company</strong><small>Internal operations</small></div>
          <button className="lc-close" type="button" onClick={onClose} aria-label="Close"><LandingIcon name="close" size={16} /></button>
        </div>
        {error && <div className="alert">{error}</div>}
        <div className="field"><label>Email</label><input type="email" value={form.email} onChange={(event) => set("email", event.target.value)} placeholder="info@appligator.de" autoComplete="email" required /></div>
        <div className="field"><label>Password</label><input type="password" value={form.password} onChange={(event) => set("password", event.target.value)} autoComplete="current-password" minLength={8} required /></div>
        <button className="btn lg" type="submit" style={{ width: "100%" }} disabled={busy}>{busy ? "Signing in..." : "Sign in"}</button>
        <div className="lc-foot">Operations workspace · authorised staff only</div>
      </form>
    </div>
  );
}

function hexToRgb(h) { const n = parseInt(h.slice(1), 16); return [(n >> 16) & 255, (n >> 8) & 255, n & 255]; }
function shade(h, pct) { const [r, g, b] = hexToRgb(h); const f = (1 + pct / 100); const c = (v) => Math.max(0, Math.min(255, Math.round(v * f))); return `rgb(${c(r)},${c(g)},${c(b)})`; }
function tint(h, amt) { const [r, g, b] = hexToRgb(h); const m = (v) => Math.round(v + (255 - v) * amt); return `rgb(${m(r)},${m(g)},${m(b)})`; }

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