import { useCallback, useEffect, useMemo, useState } from "react";
import { ArrowLeft, RotateCcw, Save } from "lucide-react";
import type { BookDto } from "@readabook/shared";
import { api, getApiFallback } from "../api/client";
import { ErrorRibbon, Meter } from "../components/ui";
import { navigate } from "../router";
import { CbzReader } from "../reader/CbzReader";
import { EpubReader } from "../reader/EpubReader";
import { parseCbrPageLocator, parseCbzPageLocator, parsePdfPageLocator, pdfPagePercent } from "../reader/locators";
import { PdfReader } from "../reader/PdfReader";
import { useReaderProgress } from "../reader/useReaderProgress";

export function ReaderPage({ bookId }: { bookId: number }) {
  const [book, setBook] = useState<BookDto | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string>();
  const [page, setPage] = useState(1);
  const { progress, saving, error: progressError, save } = useReaderProgress(bookId);

  async function loadBook() {
    setLoading(true);
    setError(undefined);
    try {
      setBook(await api.book(bookId));
    } catch (loadError) {
      const fallback = getApiFallback<BookDto>(loadError);
      setBook(fallback ?? null);
      setError(fallback ? "Lecteur ouvert en mode secours." : "Ouvrage indisponible.");
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    void loadBook();
  }, [bookId]);

  useEffect(() => {
    const nextPage = parsePdfPageLocator(progress?.locator) ?? parseCbzPageLocator(progress?.locator) ?? parseCbrPageLocator(progress?.locator);
    if (nextPage) setPage((current) => (current === nextPage ? current : nextPage));
  }, [progress]);

  const fileUrl = useMemo(() => api.bookFileUrl(bookId), [bookId]);
  const savePdfPage = useCallback(
    (nextPage: number, pages: number) => {
      setPage(nextPage);
      void save(`pdf:page:${nextPage}`, pdfPagePercent(nextPage, pages));
    },
    [save]
  );
  const saveEpubLocator = useCallback((locator: string, percent: number) => void save(locator, percent), [save]);
  const saveComicPage = useCallback(
    (nextPage: number, pages: number) => {
      setPage(nextPage);
      const prefix = book?.format === "cbr" ? "cbr" : "cbz";
      void save(`${prefix}:page:${nextPage}`, pdfPagePercent(nextPage, pages));
    },
    [book?.format, save]
  );

  return (
    <div className="reader-page">
      <header className="reader-topbar">
        <button className="ghost-button" onClick={() => navigate(book ? `/book/${book.id}` : "/home")}>
          <ArrowLeft size={17} />
          Fiche
        </button>
        <div>
          <strong>{book?.title ?? "Ouverture du lecteur"}</strong>
          <span>{loading ? "Chargement" : saving ? "Sauvegarde" : "Progression synchronisee"}</span>
        </div>
        {error ? (
          <button className="ghost-button icon-only" onClick={() => void loadBook()} aria-label="Reessayer">
            <RotateCcw size={18} />
          </button>
        ) : (
          <Save size={18} />
        )}
      </header>
      <ErrorRibbon message={error ?? progressError} />
      <Meter value={progress?.percent ?? 0} />
      {!book ? (
        <div className="reader-fallback">
          <span>{error ?? "Chargement du livre."}</span>
          <button className="ghost-button" onClick={() => void loadBook()}>
            Reessayer
          </button>
        </div>
      ) : book.format === "pdf" ? (
        <PdfReader url={fileUrl} page={page} onPageCommit={savePdfPage} />
      ) : book.format === "cbz" || book.format === "cbr" ? (
        <CbzReader bookId={book.id} page={page} onPageCommit={saveComicPage} />
      ) : (
        <EpubReader url={fileUrl} locator={progress?.locator} onLocatorChange={saveEpubLocator} />
      )}
    </div>
  );
}
