import { useEffect, useState } from 'react';
import type { ReactElement } from 'react';
import type { Conversation, PublicUser, User } from '@altricade/core';
import { getPresence, heartbeat } from '@altricade/core/api';
import { SessionProvider, useSession } from '../entities/session';
import { AuthForm } from '../features/auth';
import { RealtimeProvider, useRealtime } from '../features/realtime';
import { useConversations, ConversationSidebar } from '../features/conversations';
import { ContactsPanel } from '../features/contacts';
import { ChatView } from '../features/messaging';
import { apiConfig } from '../shared/api';
import { useTheme } from '../shared/theme';
import type { ThemePreference } from '../shared/theme';

const PREFERENCES: readonly ThemePreference[] = ['light', 'dark', 'system'];

const ThemeSwitch = (): ReactElement => {
  const { preference, setPreference } = useTheme();
  return (
    <div className="theme-switch">
      {PREFERENCES.map((option) => (
        <button
          key={option}
          type="button"
          aria-pressed={preference === option}
          onClick={() => {
            setPreference(option);
          }}
        >
          {option}
        </button>
      ))}
    </div>
  );
};

const Dashboard = ({ user, onLogout }: { user: User; onLogout: () => void }): ReactElement => {
  const me: PublicUser = {
    id: user.id,
    username: user.username,
    displayName: user.displayName,
    avatarUrl: user.avatarUrl,
  };
  const { state } = useRealtime();
  const { conversations, startDirect, createGroupChat } = useConversations(user.id);
  const [current, setCurrent] = useState<Conversation | null>(null);
  const [onlineMap, setOnlineMap] = useState<Record<string, boolean>>({});

  const peerKey = conversations
    .flatMap((conversation) => (conversation.peer === null ? [] : [conversation.peer.id]))
    .join(',');

  // Poll presence for the people we have DMs with.
  useEffect(() => {
    const ids = peerKey.split(',').filter((id) => id.length > 0);
    if (ids.length === 0) {
      return undefined;
    }
    let cancelled = false;
    const poll = async (): Promise<void> => {
      try {
        const presences = await getPresence(apiConfig, ids);
        if (!cancelled) {
          const map: Record<string, boolean> = {};
          for (const presence of presences) {
            map[presence.userId] = presence.online;
          }
          setOnlineMap(map);
        }
      } catch {
        // presence is best-effort
      }
    };
    void poll();
    const interval = setInterval(() => {
      void poll();
    }, 20000);
    return () => {
      cancelled = true;
      clearInterval(interval);
    };
  }, [peerKey]);

  // Keep-alive heartbeat so our own last-seen stays fresh while connected.
  useEffect(() => {
    const interval = setInterval(() => {
      void heartbeat(apiConfig);
    }, 45000);
    return () => {
      clearInterval(interval);
    };
  }, []);

  return (
    <div className="layout">
      <header className="topbar">
        <span>
          <strong>@{user.username}</strong> · socket: {state}
        </span>
        <span className="topbar-actions">
          <ThemeSwitch />
          <button type="button" onClick={onLogout}>
            Log out
          </button>
        </span>
      </header>
      <div className="workspace">
        <div className="sidebar-column">
          <ConversationSidebar
            conversations={conversations}
            currentId={current?.id ?? null}
            onlineMap={onlineMap}
            onSelect={setCurrent}
            onStartDirect={async (username) => {
              setCurrent(await startDirect(username));
            }}
            onCreateGroup={async (title, members) => {
              setCurrent(await createGroupChat(title, members));
            }}
          />
          <ContactsPanel
            onStartDirect={async (username) => {
              setCurrent(await startDirect(username));
            }}
          />
        </div>
        {current !== null ? (
          <ChatView conversation={current} me={me} />
        ) : (
          <section className="chat chat-empty">
            <p>Search for a user or pick a contact to start chatting.</p>
          </section>
        )}
      </div>
    </div>
  );
};

const Shell = (): ReactElement => {
  const { status, user, logout } = useSession();

  if (status === 'loading') {
    return (
      <main className="app">
        <p>Loading…</p>
      </main>
    );
  }
  if (user === null) {
    return <AuthForm />;
  }
  return (
    <RealtimeProvider>
      <Dashboard
        user={user}
        onLogout={() => {
          void logout();
        }}
      />
    </RealtimeProvider>
  );
};

export const App = (): ReactElement => (
  <SessionProvider>
    <Shell />
  </SessionProvider>
);
