import { createGuideSidebar } from "./core/guideSidebar.js";
import { NAVIGABLE_VIEWS } from "./core/sidebarData.js";
import { createInputManager } from "./core/input.js";
import { createNavigationManager } from "./core/nav.js";
import { createRouter } from "./core/router.js";
import { createAppState } from "./core/state.js";
import { createHomeView } from "./views/home/home.js";
import { createLibraryView } from "./views/library/library.js";
import { createLockView } from "./views/lock/lock.js";
import { createUserSetupView } from "./views/onboarding/userSetup.js";
import { createGuidePanelOverlay } from "./views/overlays/guidePanel.js";
import { createKeyboardOverlay } from "./views/overlays/keyboard.js";
import { createPowerMenuOverlay } from "./views/overlays/powerMenu.js";
import { createPlaceholderView } from "./views/placeholder/placeholder.js";
import { createSettingsView } from "./views/settings/settings.js";

const appRoot = document.querySelector("#app");
const overlayRoot = document.querySelector("#overlay-root");
const keyboardRoot = document.querySelector("#keyboard-root");
const footer = document.querySelector("#app-footer");
const guideShellRoot = document.querySelector("#guide-shell-root");
const guideBackdrop = document.querySelector("#guide-backdrop");

const SIDEBAR_HIDDEN_VIEWS = new Set(["lock", "user-setup"]);

const state = createAppState();
const nav = createNavigationManager();
const router = createRouter(appRoot);
const guidePanels = createGuidePanelOverlay({ mountRoot: overlayRoot });
const powerMenu = createPowerMenuOverlay({ mountRoot: overlayRoot });
const keyboard = createKeyboardOverlay({ mountRoot: keyboardRoot });

let currentViewContract = null;

const remountNavigation = (options = {}) => {
  if (!currentViewContract) return;

  currentViewContract = {
    ...currentViewContract,
    extraFocusRoots: SIDEBAR_HIDDEN_VIEWS.has(state.activeView)
      ? []
      : guideSidebar.getFocusRoots(),
    defaultFocus: options.defaultFocus ?? currentViewContract.defaultFocus,
  };

  nav.mount(currentViewContract);

  if (options.focusKey) {
    const target = document.querySelector(`[data-focus-key="${CSS.escape(options.focusKey)}"]`);
    if (target) {
      currentViewContract.defaultFocus = target;
      nav.mount(currentViewContract);
    }
  }
};

const guideSidebar = createGuideSidebar({
  state,
  renderView,
  openPowerMenu,
  openGuidePanel: (panelId) => {
    guidePanels.open(panelId, {
      onClose: () => remountNavigation(),
    });
    setFooterHints("#guide-panel-hints-template", state.glyphs);
  },
  onGuideChange: ({ expanded }) => {
    if (expanded) {
      const active = document.querySelector(
        "#guide-panel [data-sidebar-nav].is-active, #guide-panel .guide-nav-item",
      );
      remountNavigation({ defaultFocus: active ?? undefined });
      setFooterHints("#guide-hints-template", state.glyphs);
      return;
    }
    remountNavigation();
    setFooterHints(currentViewContract?.hintsTemplate ?? "#global-hints-template", state.glyphs);
  },
});

const emitUiHook = (type, payload = {}) => {
  window.dispatchEvent(
    new CustomEvent("nebula-ui-hook", {
      detail: { type, ...payload },
    }),
  );
};

const setFooterHints = (templateId, glyphs) => {
  const template = document.querySelector(templateId);
  if (!template) {
    footer.innerHTML = "";
    return;
  }
  footer.innerHTML = template.innerHTML;
  footer.querySelectorAll("[data-glyph]").forEach((element) => {
    const action = element.dataset.glyph;
    element.textContent = glyphs[action] ?? action;
  });
};

const updateClockLabels = () => {
  const now = new Date();
  const formattedTime = now.toLocaleTimeString([], {
    hour: "2-digit",
    minute: "2-digit",
  });
  const formattedDate = now.toLocaleDateString([], {
    weekday: "short",
    month: "short",
    day: "numeric",
    year: "numeric",
  });
  document.querySelectorAll("[data-clock]").forEach((clock) => {
    clock.textContent = formattedTime;
  });
  document.querySelectorAll("[data-date]").forEach((date) => {
    date.textContent = formattedDate;
  });
};

const updateSidebar = (viewId) => {
  const body = document.body;

  if (SIDEBAR_HIDDEN_VIEWS.has(viewId)) {
    body.classList.add("body-no-sidebar");
    guideSidebar.close();
    return;
  }

  body.classList.remove("body-no-sidebar");
  guideSidebar.updateActiveView(viewId);
  guideSidebar.syncProfile();
};

function renderView(viewId) {
  const contract = router.navigate(viewId);
  if (!contract) {
    return;
  }
  state.activeView = viewId;
  updateSidebar(viewId);

  if (guideSidebar.isExpanded()) {
    guideSidebar.close();
  }

  currentViewContract = {
    ...contract,
    extraFocusRoots: SIDEBAR_HIDDEN_VIEWS.has(viewId) ? [] : guideSidebar.getFocusRoots(),
  };

  nav.mount(currentViewContract);
  setFooterHints(currentViewContract.hintsTemplate ?? "#global-hints-template", state.glyphs);
  updateClockLabels();
}

const refreshNavigation = (event) => {
  if (!currentViewContract?.focusRoot) {
    return;
  }

  const focusKey = event?.detail?.focusKey;
  const requestedFocus = focusKey
    ? document.querySelector(`[data-focus-key="${CSS.escape(focusKey)}"]`)
    : null;

  remountNavigation({
    defaultFocus: requestedFocus ?? currentViewContract.defaultFocus,
  });
};

const registerViews = () => {
  const context = { state, renderView, powerMenu, keyboard, openPowerMenu };
  router.register(createUserSetupView(context));
  router.register(createLockView(context));
  router.register(createHomeView(context));
  router.register(createSettingsView(context));
  router.register(createLibraryView(context));
  router.register(
    createPlaceholderView(context, {
      id: "store",
      title: "Store",
      subtitle: "Discover",
    }),
  );
  router.register(
    createPlaceholderView(context, {
      id: "mods",
      title: "Mods",
      subtitle: "Community",
    }),
  );
};

function openPowerMenu() {
  if (guideSidebar.isExpanded()) {
    guideSidebar.close();
  }
  powerMenu.open({
    onClose: () => {
      remountNavigation();
      setFooterHints(currentViewContract?.hintsTemplate ?? "#global-hints-template", state.glyphs);
    },
  });
  setFooterHints("#minimal-hints-template", state.glyphs);
}

const toggleGuide = () => {
  if (SIDEBAR_HIDDEN_VIEWS.has(state.activeView)) {
    return;
  }
  guideSidebar.toggle();
};

const handleGuideAccept = (focused) => {
  const handled = guideSidebar.handleAccept(focused);
  if (handled) {
    remountNavigation({ focusKey: focused?.dataset?.focusKey });
  }
};

const handleAction = (action) => {
  if (powerMenu.isOpen()) {
    powerMenu.handleAction(action);
    return;
  }

  if (guidePanels.isOpen()) {
    if (guidePanels.handleAction(action)) {
      return;
    }
  }

  if (keyboard.isOpen()) {
    const consumed = keyboard.handleAction(action);
    if (consumed) {
      return;
    }
  }

  if (!currentViewContract) {
    return;
  }

  if (action === "guide") {
    toggleGuide();
    return;
  }

  if (action === "menu") {
    if (SIDEBAR_HIDDEN_VIEWS.has(state.activeView)) {
      currentViewContract.onMenu?.();
      return;
    }

    if (guideSidebar.isExpanded()) {
      guideSidebar.close();
      return;
    }
    toggleGuide();
    return;
  }

  if (guideSidebar.isExpanded()) {
    if (action === "back") {
      guideSidebar.close();
      return;
    }

    if (action === "up" || action === "down" || action === "left" || action === "right") {
      nav.move(action);
      emitUiHook("move", { action });
      return;
    }

    if (action === "accept") {
      const focused = nav.getFocusedElement();
      focused?.classList.add("is-pressed");
      window.setTimeout(() => focused?.classList.remove("is-pressed"), 180);
      handleGuideAccept(focused);
      return;
    }

    return;
  }

  if (action === "up" || action === "down" || action === "left" || action === "right") {
    if (currentViewContract.captureDirectionalInput) {
      const handled = currentViewContract.onAction?.(action, nav.getFocusedElement());
      if (handled) {
        return;
      }
    }

    nav.move(action);
    emitUiHook("move", { action });
    return;
  }

  if (action === "accept") {
    const focused = nav.getFocusedElement();
    focused?.classList.add("is-pressed");
    window.setTimeout(() => focused?.classList.remove("is-pressed"), 180);
    emitUiHook("accept", { focusKey: focused?.dataset.focusKey ?? null });

    if (focused?.dataset.navRegion === "sidebar") {
      if (focused.dataset.guideAction === "toggle") {
        guideSidebar.open();
        return;
      }
      if (focused.dataset.guideAction === "power") {
        openPowerMenu();
        return;
      }
      const target = focused.dataset.target;
      if (target && NAVIGABLE_VIEWS.has(target)) {
        renderView(target);
      }
      return;
    }

    currentViewContract.onAccept?.(focused);
    return;
  }

  if (action === "back") {
    emitUiHook("back");
    currentViewContract.onBack?.();
    return;
  }

  currentViewContract.onAction?.(action, nav.getFocusedElement());
};

const initialize = async () => {
  guideSidebar.mount({
    shellRoot: guideShellRoot,
    backdropRoot: guideBackdrop,
  });

  await state.initializeUser();
  await state.initializeNebulaCore();
  state.startGamepadProfileWatcher?.();
  registerViews();
  renderView(state.userSetupRequired ? "user-setup" : "lock");
  updateClockLabels();
  window.setInterval(updateClockLabels, 1000);

  window.addEventListener("nebula-navigation-refresh", refreshNavigation);
  window.addEventListener("nebula-controller-profile", () => {
    setFooterHints(currentViewContract?.hintsTemplate ?? "#global-hints-template", state.glyphs);
  });
  window.addEventListener("nebula-guide-close", (event) => {
    remountNavigation({ focusKey: event.detail?.focusKey });
  });

  window.addEventListener("keydown", (event) => {
    if (event.key === "Escape" && guideSidebar.isExpanded()) {
      event.preventDefault();
      guideSidebar.close();
    }
  });

  const input = createInputManager({
    onAction: handleAction,
    actions: [
      "up",
      "down",
      "left",
      "right",
      "accept",
      "back",
      "menu",
      "guide",
      "clear",
      "y",
      "l1",
      "r1",
      "l2",
      "r2",
    ],
  });

  input.start();
};

initialize();
