import { useCallback, useEffect, useMemo, useState } from "react";
import "./styles/normalize.css";
import "./styles/index.css";
import { Sidebar, type NewAccountInput } from "./components/Sidebar";
import { ColumnBoard } from "./components/ColumnBoard";
import { AddColumnModal } from "./components/AddColumnModal";
import { usePersistentState } from "./hooks/usePersistentState";
import type {
  ColumnSnapshot,
  ColumnState,
  DeckAccount,
  DeckColumn,
  DeckListsCache,
  FullscreenState,
} from "./types/app";
import type { Tweet } from "./lib/fetching/types";
import { generateId } from "./lib/utils/id";
import { twitterClient } from "./lib/client/twitterClient";
import { FullscreenColumn } from "./components/FullscreenColumn";

const ACCOUNTS_KEY = "tweetdeck.accounts";
const COLUMNS_KEY = "tweetdeck.columns";

export function App() {
  const [accounts, setAccounts] = usePersistentState<DeckAccount[]>(
    ACCOUNTS_KEY,
    [],
  );
  const [columns, setColumns] = usePersistentState<DeckColumn[]>(
    COLUMNS_KEY,
    [],
  );
  const [listsCache, setListsCache] = useState<DeckListsCache>({});
  const [activeAccountId, setActiveAccountId] = useState<string | undefined>(
    () => accounts[0]?.id,
  );
  const [isModalOpen, setModalOpen] = useState(false);
  const [toast, setToast] = useState<string | null>(null);
  const [fullscreen, setFullscreen] = useState<FullscreenState | null>(null);
  const [columnSnapshots, setColumnSnapshots] = useState<
    Record<string, ColumnSnapshot>
  >({});

  useEffect(() => {
    if (!activeAccountId) {
      const firstAccount = accounts[0];
      if (firstAccount) {
        setActiveAccountId(firstAccount.id);
      }
    }
  }, [accounts, activeAccountId]);

  useEffect(() => {
    const acs = accounts.filter((a) => !a.avatar || !a.username);
    console.log({ acs });
    const nacs = acs.map(async (acc) => {
      const our = await twitterClient.own({ cookie: acc.cookie });
      const nacc = {
        ...acc,
        handle: our.username,
        label: our.name,
        avatar: our.avatar,
      };
      return nacc;
    });
    Promise.all(nacs)
      .then((acs) => setAccounts(acs))
      .catch((err) => console.error(err));
  }, []);

  const handleAddAccount = useCallback(
    (payload: NewAccountInput) => {
      const label = `Session ${accounts.length + 1}`;
      const account: DeckAccount = {
        id: generateId(),
        label,
        accent: randomAccent(),
        cookie: payload.cookie.trim(),
        createdAt: Date.now(),
      };
      setAccounts((prev) => [...prev, account]);
      setActiveAccountId(account.id);
      setToast(`${account.label} is ready`);
    },
    [accounts.length, setAccounts],
  );

  const handleRemoveAccount = useCallback(
    (accountId: string) => {
      setAccounts((prev) => prev.filter((account) => account.id !== accountId));
      setColumns((prev) =>
        prev.filter((column) => column.accountId !== accountId),
      );
      setListsCache((prev) => {
        const next = { ...prev };
        delete next[accountId];
        return next;
      });
      if (activeAccountId === accountId) {
        setActiveAccountId(undefined);
      }
    },
    [activeAccountId, setAccounts, setColumns],
  );

  const handleAddColumn = useCallback(
    (column: Omit<DeckColumn, "id">) => {
      const nextColumn = { ...column, id: generateId() };
      setColumns((prev) => [...prev, nextColumn]);
      setToast(`${nextColumn.title} added to deck`);
    },
    [setColumns],
  );

  const handleRemoveColumn = useCallback(
    (id: string) => {
      setColumns((prev) => prev.filter((column) => column.id !== id));
    },
    [setColumns],
  );

  const fetchLists = useCallback(
    async (accountId: string) => {
      const account = accounts.find((acc) => acc.id === accountId);
      if (!account) throw new Error("Account not found");
      if (listsCache[accountId]) return listsCache[accountId];
      console.log({ listsCache });
      const lists = await twitterClient.lists({ cookie: account.cookie });
      console.log({ lists });
      setListsCache((prev) => ({ ...prev, [accountId]: lists }));
      return lists;
    },
    [accounts, listsCache],
  );

  const handleColumnStateChange = useCallback(
    (columnId: string, state: ColumnState) => {
      setColumns((prev) =>
        prev.map((column) =>
          column.id === columnId ? { ...column, state } : column,
        ),
      );
    },
    [setColumns],
  );

  const handleColumnSnapshot = useCallback(
    (columnId: string, snapshot: ColumnSnapshot) => {
      setColumnSnapshots((prev) => {
        const existing = prev[columnId];
        if (
          existing &&
          existing.tweets === snapshot.tweets &&
          existing.label === snapshot.label
        ) {
          return prev;
        }
        return {
          ...prev,
          [columnId]: { tweets: snapshot.tweets, label: snapshot.label },
        };
      });
    },
    [],
  );

  const openFullscreen = useCallback(
    (payload: FullscreenState) => {
      const snapshot = columnSnapshots[payload.column.id];
      setFullscreen({
        ...payload,
        tweets: snapshot?.tweets ?? payload.tweets,
        columnLabel: snapshot?.label ?? payload.columnLabel,
      });
    },
    [columnSnapshots],
  );

  useEffect(() => {
    if (!fullscreen) return;
    const snapshot = columnSnapshots[fullscreen.column.id];
    if (!snapshot) return;
    if (
      snapshot.tweets === fullscreen.tweets &&
      snapshot.label === fullscreen.columnLabel
    ) {
      return;
    }
    setFullscreen((prev) => {
      if (!prev) return prev;
      if (prev.column.id !== fullscreen.column.id) return prev;
      const tweets = snapshot.tweets;
      const index = Math.min(prev.index, Math.max(tweets.length - 1, 0));
      return {
        ...prev,
        tweets,
        columnTitle: snapshot.label,
        index,
      };
    });
  }, [columnSnapshots, fullscreen]);

  const content = useMemo(
    () => (
      <ColumnBoard
        columns={columns}
        accounts={accounts}
        onRemove={handleRemoveColumn}
        onStateChange={handleColumnStateChange}
        onSnapshot={handleColumnSnapshot}
        onEnterFullscreen={openFullscreen}
      />
    ),
    [
      accounts,
      columns,
      handleRemoveColumn,
      handleColumnStateChange,
      handleColumnSnapshot,
      openFullscreen,
    ],
  );

  return (
    <div className="app-shell">
      <Sidebar
        accounts={accounts}
        activeAccountId={activeAccountId}
        onActivate={(id) => setActiveAccountId(id)}
        onAddAccount={handleAddAccount}
        onRemoveAccount={handleRemoveAccount}
        onAddColumn={() => setModalOpen(true)}
      />

      <main>{content}</main>

      <AddColumnModal
        accounts={accounts}
        activeAccountId={activeAccountId}
        isOpen={isModalOpen}
        onClose={() => setModalOpen(false)}
        onAdd={handleAddColumn}
        fetchLists={fetchLists}
        listsCache={listsCache}
      />

      {toast && (
        <div className="toast" onAnimationEnd={() => setToast(null)}>
          {toast}
        </div>
      )}

      {fullscreen && (
        <FullscreenColumn
          state={fullscreen}
          onExit={() => setFullscreen(null)}
          onNavigate={(step) => {
            setFullscreen((prev) => {
              if (!prev) return prev;
              if (!prev.tweets.length) return prev;
              const nextIndex = Math.min(
                prev.tweets.length - 1,
                Math.max(0, prev.index + step),
              );
              if (nextIndex === prev.index) return prev;
              return { ...prev, index: nextIndex };
            });
          }}
          hasPrevColumn={fullscreen.columnIndex > 0}
          hasNextColumn={fullscreen.columnIndex < columns.length - 1}
          onSwitchColumn={(direction) => {
            setFullscreen((prev) => {
              if (!prev) return prev;
              const nextIndex = prev.columnIndex + direction;
              if (nextIndex < 0) return prev;
              if (nextIndex >= columns.length) {
                setModalOpen(true);
                return prev;
              }
              const nextColumn = columns[nextIndex];
              if (!nextColumn) return prev;
              const snapshot = columnSnapshots[nextColumn.id];
              const account = accounts.find(
                (acc) => acc.id === nextColumn.accountId,
              );
              const tweets = snapshot?.tweets ?? [];
              return {
                column: nextColumn,
                columnIndex: nextIndex,
                columnLabel: snapshot?.label ?? nextColumn.title,
                accent: account?.accent ?? prev.accent,
                tweets,
                index: 0,
              };
            });
          }}
          onAddColumn={() => setModalOpen(true)}
        />
      )}
    </div>
  );
}

function randomAccent(): string {
  const palette = ["#7f5af0", "#2cb67d", "#f25f4c", "#f0a500", "#19a7ce"];
  const pick = palette[Math.floor(Math.random() * palette.length)];
  return pick ?? "#7f5af0";
}

export default App;
