"use client";

import {
  useCallback,
  useEffect,
  useMemo,
  useState,
} from "react";
import { usePathname } from "next/navigation";

import type {
  RgcDecisionLanguage,
} from "../data/rgc-decision-i18n";

const API_BASE_URL =
  process.env.NEXT_PUBLIC_API_URL?.replace(/\/$/, "") ??
  "http://localhost:3001/api/v1";

const PAGE = "rgc_decision";
const EMPTY_DICTIONARY: TranslationDictionary = {};

type TranslationDictionary = Record<string, string>;

type UnknownRecord = Record<string, unknown>;

const dictionaryCache = new Map<
  string,
  Promise<TranslationDictionary>
>();

function isObject(value: unknown): value is UnknownRecord {
  return value !== null && typeof value === "object" && !Array.isArray(value);
}

function getAccessToken(): string | null {
  if (typeof window === "undefined") {
    return null;
  }

  return (
    window.localStorage.getItem("accessToken") ||
    window.localStorage.getItem("access_token") ||
    window.localStorage.getItem("token")
  );
}

function unwrapDictionary(payload: unknown): TranslationDictionary {
  let current = payload;

  // Support both normal and nested API response envelopes.
  for (let index = 0; index < 3; index += 1) {
    if (!isObject(current)) {
      break;
    }

    if (isObject(current.translations)) {
      const result: TranslationDictionary = {};

      for (const [key, value] of Object.entries(current.translations)) {
        if (typeof value === "string" && value.trim()) {
          result[key] = value.trim();
        }
      }

      return result;
    }

    if ("data" in current) {
      current = current.data;
      continue;
    }

    break;
  }

  return {};
}

async function requestDictionary(
  language: RgcDecisionLanguage,
  moduleName: "cdc" | "cefp",
): Promise<TranslationDictionary> {
  const apiLanguage = language === "kh" ? "km" : "en";
  const cacheKey = `${moduleName}:${PAGE}:${apiLanguage}`;

  const cached = dictionaryCache.get(cacheKey);
  if (cached) {
    return cached;
  }

  const request = (async () => {
    const query = new URLSearchParams({
      language: apiLanguage,
      module: moduleName,
      page: PAGE,
    });

    const token = getAccessToken();

    const response = await fetch(
      `${API_BASE_URL}/translations/dictionary?${query.toString()}`,
      {
        method: "GET",
        credentials: "include",
        cache: "no-store",
        headers: {
          Accept: "application/json",
          ...(token
            ? {
                Authorization: `Bearer ${token}`,
              }
            : {}),
        },
      },
    );

    if (!response.ok) {
      throw new Error(
        `Unable to load RGC Decision translations (${response.status}).`,
      );
    }

    const body = (await response.json()) as unknown;
    return unwrapDictionary(body);
  })();

  dictionaryCache.set(cacheKey, request);

  try {
    return await request;
  } finally {
    dictionaryCache.delete(cacheKey);
  }
}

export type RgcDecisionTranslate = (
  key: string,
  fallback: string,
) => string;

export function useRgcDecisionTranslations(
  language: RgcDecisionLanguage,
) {
  const pathname = usePathname();
  const moduleName = pathname.startsWith("/cdc/rgc-decision") ? "cdc" : "cefp";
  const scope = `${moduleName}:${language}`;
  const [state, setState] = useState<{ scope: string; dictionary: TranslationDictionary }>({ scope: "", dictionary: {} });

  useEffect(() => {
    let cancelled = false;

    const load = () => requestDictionary(language, moduleName)
      .then((nextDictionary) => {
        if (!cancelled) {
          setState({ scope, dictionary: nextDictionary });
        }
      })
      .catch(() => {
        if (!cancelled) {
          setState({ scope, dictionary: {} });
        }
      });
    void load();
    const refresh = () => { void load(); };
    window.addEventListener("focus", refresh);

    return () => {
      cancelled = true;
      window.removeEventListener("focus", refresh);
    };
  }, [language, moduleName, scope]);

  const dictionary = state.scope === scope ? state.dictionary : EMPTY_DICTIONARY;

  const translate = useCallback<RgcDecisionTranslate>(
    (key, fallback) => {
      const value = dictionary[key];
      return typeof value === "string" && value.trim()
        ? value.trim()
        : fallback;
    },
    [dictionary],
  );

  return useMemo(
    () => ({
      dictionary,
      t: translate,
    }),
    [dictionary, translate],
  );
}

export default useRgcDecisionTranslations;
