"use client";
import { isSidebarTranslation } from "../sidebar-translation-keys";

import {
  useEffect,
  useMemo,
  useReducer,
} from "react";

import {
  getSidebarNavItemsByPathname,
  type NavItem,
} from "@/constants/sidebar-menu";

import {
  getSidebarTranslations,
  type SidebarTranslation,
  type SidebarTranslationModule,
} from "@/constants/service/sidebar-translation-service";

import {
  isAdminRole,
  isCdcGpsfRole,
  isCdcRole,
  isCefpRole,
  isMinistryRole,
  type AuthPermission,
  type UserRole,
} from "@/features/auth/auth-data";

import type { LanguageCode } from "@/components/layout/header/header-data";

/* =========================================================
 * TYPES
 * ======================================================= */

type ApiState = {
  moduleKey: SidebarTranslationModule | null;
  items: SidebarTranslation[];
};

type ApiAction =
  | {
      type: "loaded";
      moduleKey: SidebarTranslationModule;
      items: SidebarTranslation[];
    }
  | {
      type: "failed";
      moduleKey: SidebarTranslationModule;
    };

type TranslationNode = {
  item: SidebarTranslation;
  children: TranslationNode[];
};

/* =========================================================
 * INITIAL STATE
 * ======================================================= */

const initialApiState: ApiState = {
  moduleKey: null,
  items: [],
};

/* =========================================================
 * REDUCER
 * ======================================================= */

function apiStateReducer(
  state: ApiState,
  action: ApiAction,
): ApiState {
  switch (action.type) {
    case "loaded":
      return {
        moduleKey: action.moduleKey,
        items: action.items,
      };

    case "failed":
      return {
        moduleKey: action.moduleKey,
        items: [],
      };

    default:
      return state;
  }
}

/* =========================================================
 * GET MODULE FROM PATH
 * ======================================================= */

function getSidebarModule(
  pathname: string,
  role: UserRole | null,
): SidebarTranslationModule | null {
  /*
   * ADMIN DOES NOT USE SIDEBAR TRANSLATION API
   */
  if (
    pathname === "/admin" ||
    pathname.startsWith("/admin/") ||
    isAdminRole(role)
  ) {
    return null;
  }

  /*
   * PATH HAS PRIORITY
   */

  if (pathname.startsWith("/cdc-gpsf")) {
    return "cdcgpsf";
  }

  if (pathname.startsWith("/ministry")) {
    return "ministry";
  }

  if (pathname.startsWith("/pswg")) {
    return "pswg";
  }

  if (pathname.startsWith("/cdc")) {
    return "cdc";
  }

  if (pathname.startsWith("/cefp")) {
    return "cefp";
  }

  /*
   * ROLE FALLBACK
   */

  if (isCdcGpsfRole(role)) {
    return "cdcgpsf";
  }

  if (isMinistryRole(role)) {
    return "ministry";
  }

  if (isCdcRole(role)) {
    return "cdc";
  }

  if (isCefpRole(role)) {
    return "cefp";
  }

  return "pswg";
}

/* =========================================================
 * NORMALIZE
 * ======================================================= */

function normalizeText(
  value: string | null | undefined,
): string {
  return String(value ?? "")
    .trim()
    .toLowerCase()
    .replace(/[_-]+/g, " ")
    .replace(/\s+/g, " ");
}

/* =========================================================
 * GET API PAGE FROM STATIC URL
 *
 * Examples:
 *
 * /cdc-gpsf/dashboard
 *      => dashboard
 *
 * /cdc-gpsf/meeting-requests
 *      => meeting_requests
 *
 * /cdc-gpsf/plenary/dashboard
 *      => plenary_dashboard
 *
 * /cdc-gpsf/plenary/plenaries
 *      => plenary_plenaries
 *
 * /cdc-gpsf/plenary/rgc-decisions
 *      => plenary_rgc_decisions
 * ======================================================= */

function getExpectedPageFromUrl(
  item: NavItem,
  moduleKey: SidebarTranslationModule,
): string | null {
  if (!item.url) {
    return null;
  }

  const segments = item.url
    .split("/")
    .filter(Boolean);

  if (segments.length < 2) {
    return null;
  }

  const routeModule = segments[0];

  const expectedRouteModule =
    moduleKey === "cdcgpsf"
      ? "cdc-gpsf"
      : moduleKey;

  if (routeModule !== expectedRouteModule) {
    return null;
  }

  const routeSegments = segments.slice(1);

  return routeSegments
    .map((segment) =>
      segment
        .trim()
        .replace(/-/g, "_"),
    )
    .join("_");
}

/* =========================================================
 * BUILD TREE
 * ======================================================= */

function buildTranslationTree(
  translations: SidebarTranslation[],
): TranslationNode[] {
  /*
   * IMPORTANT:
   *
   * We keep every translation record.
   *
   * Parent:
   *   page = sidebar
   *
   * Child:
   *   parentId = parent.id
   */

  const nodeById = new Map<
    number,
    TranslationNode
  >();

  for (const item of translations) {
    if (!isSidebarTranslation(item)) continue;
    nodeById.set(item.id, {
      item,
      children: [],
    });
  }

  const roots: TranslationNode[] = [];

  for (const node of nodeById.values()) {
    const parentId = node.item.parentId ?? null;

    if (
      parentId !== null &&
      nodeById.has(parentId)
    ) {
      nodeById
        .get(parentId)!
        .children.push(node);
    } else {
      roots.push(node);
    }
  }

  /*
   * Sort children by ID
   */
  for (const node of nodeById.values()) {
    node.children.sort(
      (a, b) => a.item.id - b.item.id,
    );
  }

  /*
   * Sort roots by ID
   */
  roots.sort(
    (a, b) => a.item.id - b.item.id,
  );

  return roots;
}

/* =========================================================
 * FIND TRANSLATION BY PAGE
 * ======================================================= */

function findTranslationByPage(
  item: NavItem,
  candidates: TranslationNode[],
  moduleKey: SidebarTranslationModule,
): TranslationNode | null {
  const expectedPage = getExpectedPageFromUrl(item, moduleKey);

  if (!expectedPage) {
    return null;
  }

  const normalizedExpected = normalizeText(expectedPage);
  const expectedEnglish = normalizeText(item.titleEn);

  // Stable key first: Admin may change the English sidebar text independently.
  const sidebarTitle = candidates.find(
    node => normalizeText(node.item.page) === normalizedExpected &&
      node.item.translationKey === "title",
  );
  if (sidebarTitle) return sidebarTitle;

  // First try to match BOTH page and english text
  const exactMatch = candidates.find(
    (node) =>
      normalizeText(node.item.page) === normalizedExpected &&
      normalizeText(node.item.englishText) === expectedEnglish
  );

  if (exactMatch) {
    return exactMatch;
  }

  // Fallback to finding the first match by page
  return (
    candidates.find(
      (node) =>
        normalizeText(
          node.item.page,
        ) === normalizedExpected,
    ) ?? null
  );
}

/* =========================================================
 * FIND TRANSLATION BY ENGLISH
 * ======================================================= */

function findTranslationByEnglish(
  item: NavItem,
  candidates: TranslationNode[],
): TranslationNode | null {
  const expectedEnglish = normalizeText(item.titleEn);

  if (!expectedEnglish) {
    return null;
  }

  // First try to match an item explicitly created for the sidebar
  const exactMatch = candidates.find(
    (node) =>
      normalizeText(node.item.englishText) === expectedEnglish &&
      normalizeText(node.item.page) === "sidebar"
  );

  if (exactMatch) {
    return exactMatch;
  }

  // Fallback to any matching english text
  return (
    candidates.find(
      (node) =>
        normalizeText(
          node.item.englishText,
        ) === expectedEnglish,
    ) ?? null
  );
}

/* =========================================================
 * FIND CHILD NODE
 * ======================================================= */

function findChildNode(
  staticChild: NavItem,
  parentNode: TranslationNode,
  moduleKey: SidebarTranslationModule,
): TranslationNode | null {
  const expectedEnglish = normalizeText(staticChild.titleEn);

  /*
   * FIRST:
   * Match explicit 'sidebar' page translations.
   */
  const sidebarExplicit = parentNode.children.find(
    (node) =>
      normalizeText(node.item.page) === "sidebar" &&
      normalizeText(node.item.englishText) === expectedEnglish
  );

  if (sidebarExplicit) {
    return sidebarExplicit;
  }

  /*
   * SECOND:
   * Match by exact API page.
   */
  const byPage = findTranslationByPage(
    staticChild,
    parentNode.children,
    moduleKey,
  );

  if (byPage) {
    return byPage;
  }

  /*
   * THIRD:
   * Match English text.
   */
  return findTranslationByEnglish(
    staticChild,
    parentNode.children,
  );
}

/* =========================================================
 * SCORE PARENT
 *
 * THIS IS THE IMPORTANT FIX.
 *
 * Parent is identified by its children,
 * NOT by array position.
 * ======================================================= */

function scoreParent(
  staticParent: NavItem,
  apiParent: TranslationNode,
  moduleKey: SidebarTranslationModule,
): number {
  if (
    staticParent.items.length === 0
  ) {
    return 0;
  }

  let score = 0;

  for (
    const staticChild of staticParent.items
  ) {
    const child =
      findChildNode(
        staticChild,
        apiParent,
        moduleKey,
      );

    if (child) {
      score += 1;
    }
  }

  return score;
}

/* =========================================================
 * FIND CORRECT PARENT
 * ======================================================= */

function findCorrectParent(
  staticParent: NavItem,
  apiRoots: TranslationNode[],
  moduleKey: SidebarTranslationModule,
  usedRootIds: Set<number>,
): TranslationNode | null {
  const candidates =
    apiRoots.filter(
      (node) =>
        !usedRootIds.has(
          node.item.id,
        ),
    );

  if (candidates.length === 0) {
    return null;
  }

  /*
   * =======================================================
   * STEP 1
   * Exact child-page matching
   * =======================================================
   */

  const scored = candidates
    .map((candidate) => ({
      candidate,
      score: scoreParent(
        staticParent,
        candidate,
        moduleKey,
      ),
    }))
    .filter(
      (result) =>
        result.score > 0,
    )
    .sort(
      (a, b) =>
        b.score - a.score,
    );

  /*
   * =======================================================
   * STEP 2
   * Return the parent with the highest child match.
   * =======================================================
   */

  if (scored.length > 0) {
    /*
     * IMPORTANT:
     *
     * Do NOT use array-position fallback.
     *
     * WG:
     *   dashboard
     *   meeting_requests
     *   meeting_calendar
     *   meeting_summary
     *   issue_matrix
     *
     * should always resolve to parent 383.
     */

    return scored[0].candidate;
  }

  /*
   * =======================================================
   * STEP 3
   * Parent English fallback
   * =======================================================
   */

  const byEnglish =
    findTranslationByEnglish(
      staticParent,
      candidates,
    );

  if (byEnglish) {
    return byEnglish;
  }

  return null;
}

/* =========================================================
 * TRANSLATE ITEM
 * ======================================================= */

function translateItem(
  staticItem: NavItem,
  apiNode: TranslationNode | null,
  language: LanguageCode,
): NavItem {
  if (!apiNode) {
    return staticItem;
  }

  const titleEn =
    apiNode.item.englishText?.trim() ||
    staticItem.titleEn;

  const titleKh =
    apiNode.item.khmerText?.trim() ||
    staticItem.titleKh;

  return {
    ...staticItem,

    /*
     * KEEP:
     *
     * url
     * icon
     * permissions
     * other static properties
     */

    titleEn,
    titleKh,

    title:
      language === "kh"
        ? titleKh
        : titleEn,
  };
}

/* =========================================================
 * APPLY TRANSLATION
 * ======================================================= */

function applyTranslations(
  staticItems: NavItem[],
  translations: SidebarTranslation[],
  moduleKey: SidebarTranslationModule,
  language: LanguageCode,
): NavItem[] {
  const apiRoots =
    buildTranslationTree(
      translations,
    );

  const usedRootIds =
    new Set<number>();

  return staticItems.map(
    (staticItem) => {
      /*
       * =====================================================
       * LEAF ITEM
       * =====================================================
       */

      if (staticItem.items.length === 0) {
        const expectedEnglish = normalizeText(staticItem.titleEn);
        
        // 1. Explicit sidebar match
        let apiNode = apiRoots.find(
          (node) =>
            normalizeText(node.item.englishText) === expectedEnglish &&
            normalizeText(node.item.page) === "sidebar"
        ) ?? null;

        // 2. Exact match by API page
        if (!apiNode) {
          apiNode = findTranslationByPage(staticItem, apiRoots, moduleKey);
        }

        // 3. Fallback to English text
        if (!apiNode) {
          apiNode = findTranslationByEnglish(staticItem, apiRoots);
        }

        if (apiNode) {
          usedRootIds.add(apiNode.item.id);
        }

        return translateItem(staticItem, apiNode, language);
      }

      /*
       * =====================================================
       * PARENT ITEM
       * =====================================================
       */

      const parentNode =
        findCorrectParent(
          staticItem,
          apiRoots,
          moduleKey,
          usedRootIds,
        );

      /*
       * No API parent:
       * keep static parent and children.
       */
      if (!parentNode) {
        return staticItem;
      }

      usedRootIds.add(
        parentNode.item.id,
      );

      /*
       * =====================================================
       * TRANSLATE CHILDREN
       * =====================================================
       */

      const children =
        staticItem.items.map(
          (staticChild) => {
            const apiChild =
              findChildNode(
                staticChild,
                parentNode,
                moduleKey,
              );

            return translateItem(
              staticChild,
              apiChild,
              language,
            );
          },
        );

      /*
       * =====================================================
       * RETURN PARENT
       * =====================================================
       */

      return {
        ...translateItem(
          staticItem,
          parentNode,
          language,
        ),

        /*
         * KEEP STATIC CHILD STRUCTURE
         */
        items: children,
      };
    },
  );
}

/* =========================================================
 * MAIN HOOK
 * ======================================================= */

export function useSidebarNavItemsByPathname(
  pathname: string,
  role: UserRole | null,
  language: LanguageCode,
  permissions: AuthPermission[] = [],
): NavItem[] {
  /*
   * =======================================================
   * STATIC NAV
   * =======================================================
   */

  const staticItems =
    useMemo(
      () =>
        getSidebarNavItemsByPathname(
          pathname,
          role,
          language,
          permissions,
        ),
      [
        pathname,
        role,
        language,
        permissions,
      ],
    );

  /*
   * =======================================================
   * MODULE
   * =======================================================
   */

  const moduleKey =
    useMemo(
      () =>
        getSidebarModule(
          pathname,
          role,
        ),
      [
        pathname,
        role,
      ],
    );

  /*
   * =======================================================
   * API STATE
   * =======================================================
   */

  const [
    apiState,
    dispatchApiState,
  ] = useReducer(
    apiStateReducer,
    initialApiState,
  );

  /*
   * =======================================================
   * LOAD TRANSLATION API
   * =======================================================
   */

  useEffect(() => {
    /*
     * Admin:
     * no translation API.
     */
    if (!moduleKey) {
      return;
    }

    /*
     * TypeScript is now narrowed.
     */
    const activeModuleKey: SidebarTranslationModule =
      moduleKey;

    let cancelled = false;

    /*
     * Reset old module immediately.
     */
    dispatchApiState({
      type: "failed",
      moduleKey:
        activeModuleKey,
    });

    const timer =
      window.setTimeout(() => {
        void (async () => {
          try {
            console.log(
              "[Sidebar Translation] GET:",
              activeModuleKey,
            );

            const items =
              await getSidebarTranslations(
                activeModuleKey,
              );

            if (cancelled) {
              return;
            }

            console.log(
              "[Sidebar Translation] Loaded:",
              activeModuleKey,
              items,
            );

            dispatchApiState({
              type: "loaded",
              moduleKey:
                activeModuleKey,
              items,
            });
          } catch (error) {
            if (cancelled) {
              return;
            }

            console.error(
              "[Sidebar Translation] API Error:",
              error,
            );

            dispatchApiState({
              type: "failed",
              moduleKey:
                activeModuleKey,
            });
          }
        })();
      }, 0);

    return () => {
      cancelled = true;
      window.clearTimeout(timer);
    };
  }, [moduleKey]);

  /*
   * =======================================================
   * FINAL NAVIGATION
   * =======================================================
   */

  return useMemo(() => {
    /*
     * Admin:
     * static navigation.
     */
    if (!moduleKey) {
      return staticItems;
    }

    /*
     * API is loading or failed:
     * static navigation.
     */
    if (
      apiState.moduleKey !==
        moduleKey ||
      apiState.items.length === 0
    ) {
      return staticItems;
    }

    /*
     * API loaded:
     * merge translations.
     */
    return applyTranslations(
      staticItems,
      apiState.items,
      moduleKey,
      language,
    );
  }, [
    apiState,
    language,
    moduleKey,
    staticItems,
  ]);
}
