import { useEffect, useRef, useState } from "react";
import { ReaderError, readerErrorMessage } from "./ReaderError";
import type { ReaderControls } from "./ReaderShell";
import type { ReaderMode } from "../api/types";

type FoliateLocation = {
  cfi?: string;
  fraction?: number;
  current?: number;
  total?: number;
};

type FoliateView = HTMLElement & {
  open(input: File | Blob | string): Promise<void>;
  close(): void;
  goLeft(): Promise<void>;
  goRight(): Promise<void>;
  goTo(target: string): Promise<unknown>;
  next(): Promise<void>;
  lastLocation?: FoliateLocation;
};

export function epubFileName(url: string): string {
  try {
    const base = globalThis.location?.href ?? "http://readabook.local/";
    const pathname = new URL(url, base).pathname;
    const name = pathname.split("/").filter(Boolean).at(-1);
    return name && name.includes(".") ? name : "book.epub";
  } catch {
    return "book.epub";
  }
}

function locationPercent(location: FoliateLocation): number {
  if (typeof location.fraction === "number") return Math.max(0, Math.min(100, location.fraction * 100));
  if (typeof location.current === "number" && typeof location.total === "number" && location.total > 0) {
    return Math.max(0, Math.min(100, (location.current / location.total) * 100));
  }
  return 1;
}

export function EpubReader({
  url,
  locator,
  backHref,
  mode,
  onLocatorChange,
  onControlsChange
}: {
  url: string;
  locator?: string;
  backHref: string;
  mode: ReaderMode;
  onLocatorChange: (locator: string, percent: number) => void;
  onControlsChange: (controls: ReaderControls) => void;
}) {
  const hostRef = useRef<HTMLDivElement>(null);
  const viewRef = useRef<FoliateView | null>(null);
  const locatorRef = useRef(locator);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string>();
  const [attempt, setAttempt] = useState(0);

  useEffect(() => {
    onControlsChange({
      canPrevious: !loading && !error,
      canNext: !loading && !error,
      positionLabel: loading ? "Ouverture EPUB" : "Lecture integree",
      onPrevious: () => void viewRef.current?.goLeft(),
      onNext: () => void viewRef.current?.goRight()
    });
  }, [error, loading, onControlsChange]);

  useEffect(() => {
    locatorRef.current = locator;
  }, [locator]);

  useEffect(() => {
    let cancelled = false;
    let view: FoliateView | null = null;

    async function mount() {
      try {
        setLoading(true);
        setError(undefined);
        await import("foliate-js/view.js");
        if (cancelled || !hostRef.current) return;

        const response = await fetch(url, { credentials: "include" });
        if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
        const blob = await response.blob();
        if (cancelled || !hostRef.current) return;

        view = document.createElement("foliate-view") as FoliateView;
        view.classList.add("epub-view");
        view.addEventListener("relocate", (event) => {
          const location = (event as CustomEvent<FoliateLocation>).detail;
          if (location?.cfi) onLocatorChange(location.cfi, locationPercent(location));
        });
        hostRef.current.replaceChildren(view);
        viewRef.current = view;

        const file = new File([blob], epubFileName(url), { type: blob.type || "application/epub+zip" });
        await view.open(file);
        if (cancelled) return;
        if (locatorRef.current) await view.goTo(locatorRef.current);
        else await view.next();
        setLoading(false);
      } catch (mountError) {
        if (!cancelled) {
          setError(readerErrorMessage(mountError, "EPUB indisponible"));
          setLoading(false);
        }
      }
    }

    void mount();
    return () => {
      cancelled = true;
      view?.close?.();
      view?.remove();
      if (viewRef.current === view) viewRef.current = null;
    };
  }, [attempt, onLocatorChange, url]);

  useEffect(() => {
    viewRef.current?.classList.toggle("epub-view-vertical", mode === "vertical");
    viewRef.current?.classList.toggle("epub-view-horizontal", mode === "horizontal");
  }, [mode]);

  if (error) {
    return (
      <div className="epub-reader">
        <ReaderError
          title="Lecture EPUB indisponible"
          detail="ReadaBook n'a pas pu ouvrir ce fichier dans le lecteur web."
          technicalDetail={error}
          downloadUrl={url}
          backHref={backHref}
          onRetry={() => setAttempt((value) => value + 1)}
        />
      </div>
    );
  }

  return (
    <div className={`epub-reader epub-reader-${mode}`}>
      {loading && (
        <div className="reader-fallback">
          <span>Ouverture EPUB</span>
        </div>
      )}
      <div className="epub-host" ref={hostRef} />
    </div>
  );
}
