import { useTranslations } from 'next-intl';

import { siteNavigation } from '#site/next.json.mjs';

import type {
  FormattedMessage,
  IntlMessageKeys,
  NavigationEntry,
  NavigationKeys,
} from '#site/types';
import type { RichTranslationValues } from 'next-intl';
import type { HTMLAttributeAnchorTarget } from 'react';

type Context = Record<string, RichTranslationValues>;
type Navigation = Record<string, NavigationEntry>;

type MappedNavigationEntry = {
  items: Array<[string, MappedNavigationEntry]>;
  label: FormattedMessage;
  link: string;
  target?: HTMLAttributeAnchorTarget | undefined;
  accent?: boolean;
};

// Provides Context replacement for variables within the Link. This is also something that is not going
// to happen in the future with `nodejs/nodejs.dev` codebase
const replaceLinkWithContext = (
  link: string,
  context?: RichTranslationValues
) =>
  Object.entries(context || {}).reduce(
    (finalLink, [find, replace]) =>
      finalLink.replace(
        `{${find}}`,
        typeof replace === 'string' ? replace : ''
      ),
    link
  );

const useSiteNavigation = () => {
  const t = useTranslations();

  const mapNavigationEntries = (entries: Navigation, context: Context = {}) => {
    const getFormattedMessage = (label: IntlMessageKeys, key: string) =>
      t.rich(label, context[key] || {}) as FormattedMessage;

    return Object.entries(entries).map(
      ([key, { label, link, items, target, accent }]): [
        string,
        MappedNavigationEntry,
      ] => [
        key,
        {
          target,
          accent,
          label: label ? getFormattedMessage(label, key) : '',
          link: link ? replaceLinkWithContext(link, context[key]) : '',
          items: items ? mapNavigationEntries(items, context) : [],
        },
      ]
    );
  };

  const getSideNavigation = (
    keys: Array<NavigationKeys>,
    context: Context = {}
  ) => {
    const navigationEntries: Navigation = keys.reduce(
      (acc, key) => ({ ...acc, [key]: siteNavigation.sideNavigation[key] }),
      {}
    );

    return mapNavigationEntries(navigationEntries, context);
  };

  const navigationItems = mapNavigationEntries(siteNavigation.topNavigation);

  return { getSideNavigation, navigationItems };
};

export default useSiteNavigation;
