import { filterLibraryItems } from "./libraryFilters.js";
import {
  GENRE_FILTERS,
  LIBRARY_CATEGORIES,
  createDefaultLibraryQuery,
  createMockLibraryItems,
} from "./libraryModel.js";
import { hideLibraryItem, launchLibraryItem, loadLibraryItems, scanLibraryItems } from "./libraryBridge.js";
import {
  renderCategoryTabs,
  renderDetailsPanel,
  renderFilters,
  renderGenreTabs,
  renderGrid,
  renderLibraryShell,
  renderSortPanel,
  renderSummary,
} from "./libraryComponents.js";
import { cycleOption, requestNavigationRefresh } from "./libraryController.js";

const PLAY_STATES = ["all", "played", "unplayed"];

const findItem = (runtime, id = runtime.focusedId) => runtime.items.find((item) => item.id === id) ?? null;

const focusKeyForRuntime = (runtime) => {
  if (runtime.detailsOpen) return "library-detail-0";
  if (runtime.sortOpen) return `library-sort-${runtime.query.sortBy}`;
  return runtime.focusedId ? `library-card-${runtime.focusedId}` : "library-category-games";
};

export const createLibraryView = ({ state, renderView }) => {
  const runtime = {
    items: createMockLibraryItems(),
    visibleItems: [],
    query: createDefaultLibraryQuery(),
    status: "Mock data ready",
    message: "Mock apps are shown until Start Scan imports real apps into library.db.",
    providers: [],
    focusedId: null,
    detailsOpen: false,
    sortOpen: false,
    mounted: false,
    focusListenerAttached: false,
  };

  const renderLibrary = (focusKey = null) => {
    const root = document.querySelector("[data-view='library']");
    if (!root) return;

    runtime.visibleItems = filterLibraryItems(runtime.items, runtime.query);
    if (!runtime.visibleItems.some((item) => item.id === runtime.focusedId)) {
      runtime.focusedId = runtime.visibleItems[0]?.id ?? null;
    }

    root.querySelector("[data-library-categories]").innerHTML = renderCategoryTabs(runtime.query);
    root.querySelector("[data-library-genres]").innerHTML = renderGenreTabs(runtime.query);
    root.querySelector("[data-library-summary]").innerHTML = renderSummary(
      runtime.items,
      runtime.status,
      runtime.message,
    );
    root.querySelector("[data-library-filters]").innerHTML = renderFilters(runtime.query);
    root.querySelector("[data-library-grid]").innerHTML = renderGrid(runtime.visibleItems, runtime.focusedId);

    const resultTitle = root.querySelector("[data-library-result-title]");
    const resultKicker = root.querySelector("[data-library-result-kicker]");
    const status = root.querySelector("[data-library-status]");
    if (resultTitle) resultTitle.textContent = `${runtime.visibleItems.length} Visible`;
    if (resultKicker) resultKicker.textContent = `${runtime.query.genre} · ${runtime.query.sortBy}`;
    if (status) status.textContent = runtime.message;

    const details = root.querySelector("[data-library-details]");
    details.innerHTML = runtime.detailsOpen ? renderDetailsPanel(findItem(runtime)) : "";
    details.setAttribute("aria-hidden", runtime.detailsOpen ? "false" : "true");
    details.classList.toggle("is-open", runtime.detailsOpen);

    const sortPanel = root.querySelector("[data-library-sort-panel]");
    sortPanel.innerHTML = runtime.sortOpen ? renderSortPanel(runtime.query) : "";
    sortPanel.setAttribute("aria-hidden", runtime.sortOpen ? "false" : "true");
    sortPanel.classList.toggle("is-open", runtime.sortOpen);

    requestNavigationRefresh(focusKey ?? focusKeyForRuntime(runtime));
  };

  const setLoadedState = (result) => {
    runtime.items = result.items;
    runtime.status = result.status;
    runtime.message = result.message;
    runtime.providers = result.providers;
    renderLibrary();
  };

  const refreshLibrary = async () => {
    runtime.status = "Refreshing";
    runtime.message = "Reloading library cards from library.db or mock fallback data.";
    renderLibrary("library-refresh");
    setLoadedState(await loadLibraryItems());
  };

  const scanLibrary = async () => {
    runtime.status = "Scanning device";
    runtime.message = "Checking Steam, GOG, Epic, emulator folders, and local apps for future integrations.";
    renderLibrary("library-scan");
    try {
      setLoadedState(await scanLibraryItems());
    } catch (error) {
      runtime.status = "Scan failed";
      runtime.message = String(error);
      renderLibrary("library-scan");
    }
  };

  const launchFocusedItem = async () => {
    const item = findItem(runtime);
    if (!item) return;
    const result = await launchLibraryItem(item);
    runtime.status = result?.launched ? "Launch requested" : "Details ready";
    runtime.message = result?.message ?? `${item.title} is ready.`;
    if (!item.installed) {
      runtime.detailsOpen = true;
    }
    renderLibrary();
  };

  const openDetails = () => {
    if (!runtime.focusedId) return;
    runtime.detailsOpen = true;
    runtime.sortOpen = false;
    renderLibrary("library-detail-0");
  };

  const closePanels = () => {
    runtime.detailsOpen = false;
    runtime.sortOpen = false;
    renderLibrary();
  };

  const toggleSortPanel = () => {
    runtime.sortOpen = !runtime.sortOpen;
    runtime.detailsOpen = false;
    renderLibrary(runtime.sortOpen ? `library-sort-${runtime.query.sortBy}` : focusKeyForRuntime(runtime));
  };

  const applyElementAction = async (element) => {
    if (!element) return;
    const { action } = element.dataset;

    if (action === "scan") return scanLibrary();
    if (action === "refresh") return refreshLibrary();
    if (action === "category") runtime.query.category = element.dataset.category;
    if (action === "genre") runtime.query.genre = element.dataset.genre;
    if (action === "platform") runtime.query.platform = element.dataset.platform;
    if (action === "toggle-installed") runtime.query.installedOnly = !runtime.query.installedOnly;
    if (action === "cycle-play-state") runtime.query.playState = cycleOption(PLAY_STATES, runtime.query.playState, 1);
    if (action === "toggle-coop") runtime.query.coOpOnly = !runtime.query.coOpOnly;
    if (action === "toggle-achievements") runtime.query.achievementsOnly = !runtime.query.achievementsOnly;
    if (action === "sort") runtime.query.sortBy = element.dataset.sort;

    if (action === "card") {
      runtime.focusedId = element.dataset.itemId;
      return openDetails();
    }

    if (action === "launch") return launchFocusedItem();

    if (action === "install") {
      runtime.status = "Install queued";
      runtime.message = "Store/provider install flows will connect here when integrations are added.";
    }

    if (action === "uninstall") {
      runtime.status = "Uninstall placeholder";
      runtime.message = "Uninstall will be routed through source-specific providers later.";
    }

    if (action === "hide") {
      const item = findItem(runtime);
      if (item) {
        item.hidden = true;
        await hideLibraryItem(item);
        runtime.detailsOpen = false;
        runtime.status = "Hidden";
        runtime.message = `${item.title} is hidden from the visible library.`;
      }
    }

    if (action === "open-folder") {
      runtime.status = "Open folder placeholder";
      runtime.message = "Folder opening will use the desktop bridge for installed apps.";
    }

    if (action === "close-details" || action === "close-sort") {
      return closePanels();
    }

    renderLibrary(element.dataset.focusKey);
  };

  const cycleCategory = (direction) => {
    runtime.query.category = cycleOption(
      LIBRARY_CATEGORIES.map((category) => category.id),
      runtime.query.category,
      direction,
    );
    renderLibrary(`library-category-${runtime.query.category}`);
  };

  const cycleGenre = (direction) => {
    runtime.query.genre = cycleOption(GENRE_FILTERS, runtime.query.genre, direction);
    const genreIndex = GENRE_FILTERS.findIndex((genre) => genre === runtime.query.genre);
    renderLibrary(`library-genre-${genreIndex}`);
  };

  return {
    id: "library",
    render: () => renderLibraryShell(),
    mount: async () => {
      const root = document.querySelector("[data-view='library']");
      if (!root) return;
      runtime.mounted = true;
      root.addEventListener("click", (event) => {
        const actionElement = event.target.closest("[data-action]");
        if (actionElement) {
          applyElementAction(actionElement);
        }
      });
      if (!runtime.focusListenerAttached) {
        window.addEventListener("nebula-focus-change", (event) => {
          const key = event.detail?.key ?? "";
          if (key.startsWith("library-card-")) {
            runtime.focusedId = key.replace("library-card-", "");
          }
        });
        runtime.focusListenerAttached = true;
      }
      renderLibrary("library-category-games");
      setLoadedState(await loadLibraryItems());
    },
    getNavigationContract: () => {
      const root = document.querySelector("[data-view='library']");
      return {
        focusRoot: root,
        defaultFocus: root?.querySelector("[data-focus-key='library-category-games']") ?? null,
        layout: { type: "grid", cols: 9, rows: 24 },
        hintsTemplate: "#library-hints-template",
        nebulaNavigation: state.nebula.navigation,
        useNebulaNavigation: false,
        onAccept: applyElementAction,
        onBack: () => {
          if (runtime.detailsOpen || runtime.sortOpen) {
            closePanels();
            return;
          }
          state.activeView = "home";
          renderView("home");
        },
        onMenu: () => {},
        onAction: (action, element) => {
          if (action === "y") {
            toggleSortPanel();
            return true;
          }
          if (action === "clear") {
            openDetails();
            return true;
          }
          if (action === "l1") {
            cycleCategory(-1);
            return true;
          }
          if (action === "r1") {
            cycleCategory(1);
            return true;
          }
          if (action === "l2") {
            cycleGenre(-1);
            return true;
          }
          if (action === "r2") {
            cycleGenre(1);
            return true;
          }
          if (element?.dataset.itemId) {
            runtime.focusedId = element.dataset.itemId;
            renderLibrary(element.dataset.focusKey);
          }
          return false;
        },
      };
    },
  };
};
