// Agenda — main App.
// Adds the auth screen state machine on top of the original agenda/calendar/
// projects shell: loading -> login|register|recover -> app.

const STORAGE_KEY_THEME   = 'agenda.theme.v1';
const STORAGE_KEY_VIEW    = 'agenda.view.v1';
const STORAGE_KEY_FILTERS = 'agenda.filters.v1';

function emptyDraft(date) {
  return { id: null, isNew: true, title: '', date: toISODate(date || TODAY), cat: 'personal', note: '',
           time: '', time_end: '', location_name: '', location_address: '', attachments: [] };
}

/* ─── SyncBadge ─────────────────────────────────────────────────────── */
function SyncBadge({ status }) {
  const map = {
    local:    { tone: 'muted', pulse: false },
    idle:     { tone: 'ok',    pulse: false },
    syncing:  { tone: 'work',  pulse: true  },
    saving:   { tone: 'work',  pulse: true  },
    offline:  { tone: 'err',   pulse: false },
    auth:     { tone: 'err',   pulse: false },
  };
  const m = map[status] || map.idle;
  const label = t('sync.' + status) || t('sync.idle');
  return (
    <span className={`sync sync-${m.tone}`} title={t('sync.statusLabel', { s: label })}>
      <span className={`sync-dot ${m.pulse ? 'sync-dot-pulse' : ''}`}/>
      <span className="sync-lbl">{label}</span>
    </span>
  );
}

function App() {
  const storeRef = useRef(null);
  if (!storeRef.current) storeRef.current = createStore();
  const store = storeRef.current;
  const apiBase = store.base || '';

  const [screen, setScreen] = useState('loading'); // loading | login | register | recover | app
  const [user, setUser] = useState(null);
  const [overlay, setOverlay] = useState(null); // null | 'account' | 'help'

  const [items, setItems] = useState([]);
  const [status, setStatus] = useState(store.status);
  const [view, setView] = useState(() => localStorage.getItem(STORAGE_KEY_VIEW) || 'agenda');

  const [dark, setDark] = useState(() => {
    const stored = localStorage.getItem(STORAGE_KEY_THEME);
    if (stored) return stored === 'dark';
    return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
  });
  const [filters, setFilters] = useState(() => {
    try { return JSON.parse(localStorage.getItem(STORAGE_KEY_FILTERS)) || { hidePast: false, hideDone: false }; }
    catch { return { hidePast: false, hideDone: false }; }
  });
  const [editorOpen, setEditorOpen] = useState(false);
  const [draft, setDraft] = useState(emptyDraft());
  const [monthAnchor, setMonthAnchor] = useState(TODAY);
  const [selectedDate, setSelectedDate] = useState(null);

  /* ── Resolve session once on mount ───────────────────────────────── */
  useEffect(() => {
    let cancelled = false;
    fetch('/api/auth/me', { credentials: 'same-origin' })
      .then(r => (r.ok ? r.json() : null))
      .then(data => {
        if (cancelled) return;
        window.hidePreloader && window.hidePreloader();
        if (data) {
          setLang(data.language);
          setUser(data);
          setScreen('app');
        } else {
          setScreen('login');
        }
      })
      .catch(() => { if (!cancelled) { window.hidePreloader && window.hidePreloader(); setScreen('login'); } });
    return () => { cancelled = true; };
  }, []);

  /* ── Load + subscribe to store (only once authenticated) ────────── */
  useEffect(() => {
    if (screen !== 'app') return;
    let cancelled = false;
    store.load().then(({ items }) => {
      if (cancelled) return;
      setItems(items || []);
      setStatus(store.status);
    });
    const unsub = store.subscribe(({ items, status }) => {
      if (status === 'auth') { setUser(null); setScreen('login'); return; }
      if (Array.isArray(items)) setItems(items);
      setStatus(status);
    });
    return () => { cancelled = true; unsub(); };
  }, [store, screen]);

  /* ── Persistence ─────────────────────────────────────────────────── */
  useEffect(() => {
    document.documentElement.dataset.theme = dark ? 'dark' : 'light';
    localStorage.setItem(STORAGE_KEY_THEME, dark ? 'dark' : 'light');
  }, [dark]);
  useEffect(() => {
    localStorage.setItem(STORAGE_KEY_VIEW, view);
    document.documentElement.dataset.view = view;
  }, [view]);

  /* ── Commit ──────────────────────────────────────────────────────── */
  const commit = useCallback((nextItems) => {
    setItems(nextItems);
    store.save(nextItems).then(({ items }) => {
      if (Array.isArray(items)) setItems(items);
      setStatus(store.status);
    });
  }, [store]);

  /* ── Actions ─────────────────────────────────────────────────────── */
  const openAdd = useCallback((date) => {
    setDraft(emptyDraft(date));
    setEditorOpen(true);
  }, []);
  const openEdit = useCallback((item) => {
    setDraft({
      ...item,
      isNew: false,
      time:             item.time             || '',
      time_end:         item.time_end         || '',
      location_name:    item.location_name    || item.location || '',
      location_address: item.location_address || item.location || '',
      attachments:      item.attachments      || [],
    });
    setEditorOpen(true);
  }, []);
  const closeEditor = useCallback(() => setEditorOpen(false), []);
  const saveDraft = useCallback(() => {
    if (!draft.title.trim()) return;
    const clean = {
      id:               draft.id || `it-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`,
      title:            draft.title.trim(),
      date:             draft.date,
      cat:              draft.cat,
      note:             (draft.note || '').trim(),
      time:             (draft.time || '').trim(),
      time_end:         (draft.time_end || '').trim(),
      location_name:    (draft.location_name || '').trim(),
      location_address: (draft.location_address || '').trim(),
      attachments:      draft.attachments || [],
      updatedAt:        Date.now(),
    };
    setItems(prev => {
      const idx = prev.findIndex(x => x.id === clean.id);
      const next = idx === -1 ? [...prev, clean] : prev.map(x => x.id === clean.id ? clean : x);
      Promise.resolve().then(() => commit(next));
      return next;
    });
    setEditorOpen(false);
  }, [draft, commit]);

  const toggleDone = useCallback((id) => {
    setItems(prev => {
      const next = prev.map(x => x.id === id ? { ...x, done: !x.done, updatedAt: Date.now() } : x);
      Promise.resolve().then(() => commit(next));
      return next;
    });
  }, [commit]);

  const deleteItem = useCallback((id) => {
    // Best-effort cleanup of uploaded file attachments before removing the item
    if (apiBase) {
      const item = items.find(x => x.id === id);
      if (item) {
        (item.attachments || [])
          .filter(a => a.type !== 'link')
          .forEach(a => {
            const filename = a.url.split('/').pop();
            fetch(`${apiBase}/upload/${encodeURIComponent(filename)}`, { method: 'DELETE', credentials: 'same-origin' }).catch(() => {});
          });
      }
    }
    setItems(prev => {
      const next = prev.filter(x => x.id !== id);
      Promise.resolve().then(() => commit(next));
      return next;
    });
    setEditorOpen(false);
  }, [commit, items, apiBase]);

  /* ── Filters ─────────────────────────────────────────────────────── */
  const toggleFilter = useCallback((key) => {
    setFilters(prev => {
      const next = { ...prev, [key]: !prev[key] };
      localStorage.setItem(STORAGE_KEY_FILTERS, JSON.stringify(next));
      return next;
    });
  }, []);

  const visibleItems = useMemo(() => items.filter(it => {
    if (filters.hideDone && it.done) return false;
    if (filters.hidePast && daysBetween(TODAY, fromISODate(it.date)) < 0) return false;
    return true;
  }), [items, filters]);

  /* ── Derived ─────────────────────────────────────────────────────── */
  const itemsForSelected = useMemo(() => {
    if (!selectedDate) return [];
    const iso = toISODate(selectedDate);
    return items
      .filter(x => x.date === iso)
      .sort((a, b) => {
        if (a.time && b.time) return a.time.localeCompare(b.time);
        if (a.time) return -1;
        if (b.time) return 1;
        return a.title.localeCompare(b.title);
      });
  }, [items, selectedDate]);

  /* ── Auth screens ────────────────────────────────────────────────── */
  if (screen === 'loading') return null;

  if (screen === 'login') {
    return <LoginView
      onLoggedIn={(data) => { setLang(data.language); setUser(data); setScreen('app'); }}
      onGoRegister={() => setScreen('register')}
      onGoRecover={() => setScreen('recover')}
    />;
  }
  if (screen === 'register') {
    return <RegisterView
      onRegistered={(data) => { setLang(data.language); setUser(data); setScreen('app'); }}
      onGoLogin={() => setScreen('login')}
    />;
  }
  if (screen === 'recover') {
    return <RecoverView
      onRecovered={(data) => { setLang(data.language); setUser(data); setScreen('app'); }}
      onGoLogin={() => setScreen('login')}
    />;
  }

  /* ── Main app ────────────────────────────────────────────────────── */
  return (
    <div className={`app app-${view}`}>
      <Header
        dark={dark}
        onToggleTheme={() => setDark(v => !v)}
        onAdd={() => openAdd()}
        syncStatus={status}
        view={view}
        onChangeView={setView}
        username={user?.username}
        onOpenAccount={() => setOverlay('account')}
        onOpenHelp={() => setOverlay('help')}
      />

      {view === 'projects' ? (
        <ProjectsView/>
      ) : view === 'agenda' ? (
        <main className="layout">
          <div className="col-main">
            <FilterBar filters={filters} onToggle={toggleFilter}/>
            <AgendaView
              items={visibleItems}
              onOpen={openEdit}
              onDelete={deleteItem}
              onToggleDone={toggleDone}
              onAddOnDay={openAdd}
            />
          </div>
          <aside className="col-side">
            <MiniCalendar
              items={visibleItems}
              monthAnchor={monthAnchor}
              setMonthAnchor={setMonthAnchor}
              selectedDate={selectedDate}
              setSelectedDate={setSelectedDate}
              onAddOnDay={openAdd}
            />
            {selectedDate && (
              <DayPanel
                date={selectedDate}
                items={itemsForSelected}
                onOpen={openEdit}
                onDelete={deleteItem}
                onToggleDone={toggleDone}
                onClose={() => setSelectedDate(null)}
                onAddOnDay={openAdd}
              />
            )}
          </aside>
        </main>
      ) : (
        <main className="layout layout-cal">
          <FilterBar filters={filters} onToggle={toggleFilter}/>
          <CalendarView
            items={visibleItems}
            monthAnchor={monthAnchor}
            setMonthAnchor={setMonthAnchor}
            onOpen={openEdit}
            onAddOnDay={openAdd}
            onDelete={deleteItem}
            onToggleDone={toggleDone}
          />
        </main>
      )}

      {view !== 'projects' && <FAB onAdd={() => openAdd()}/>}

      {view !== 'projects' && (
        <EditorModal
          open={editorOpen}
          draft={draft}
          onChange={setDraft}
          onSave={saveDraft}
          onCancel={closeEditor}
          onDelete={deleteItem}
          apiBase={apiBase}
        />
      )}

      {overlay === 'account' && (
        <AccountSettings
          user={user}
          onClose={() => setOverlay(null)}
          onUserChange={(u) => setUser(u)}
          onLanguageChange={(lang) => setLang(lang)}
          onLoggedOut={() => window.location.reload()}
        />
      )}
      {overlay === 'help' && (
        <HelpView user={user} onClose={() => setOverlay(null)}/>
      )}
    </div>
  );
}

window.SyncBadge = SyncBadge;

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