"use client";

import {
  useCallback,
  useEffect,
  useMemo,
  useState,
} from "react";

import {
  getTranslations,
} from "../service/translation-service";

import type {
  Translation,
  TranslationMeta,
  TranslationModule,
} from "../types/translation-types";

export type TranslationModuleFilter =
  | "all"
  | TranslationModule
  | TranslationModule[];

export type TranslationPageGroup = {
  id: number;
  module: TranslationModule;
  page: string;
  parentId: number | null;
  translationKey?: string;
  englishText: string;
  khmerText: string;
  isActive: boolean;
  labelCount: number;
  activeCount: number;
  inactiveCount: number;
  createdAt: string;
  updatedAt: string;
};

const PAGE_SIZE = 10;
export function filterTranslationPageModules(
  groups: TranslationPageGroup[],
  filter: TranslationModuleFilter,
): TranslationPageGroup[] {
  if (filter === "all" || (Array.isArray(filter) && !filter.length)) return groups;
  const modules = Array.isArray(filter) ? filter : [filter];
  return groups.filter((group) => modules.includes(group.module));
}
const API_PAGE_SIZE = 100;

const EMPTY_META: TranslationMeta = {
  page: 1,
  limit: PAGE_SIZE,
  total: 0,
  totalPages: 1,
  hasNextPage: false,
  hasPreviousPage: false,
};

function isTranslationModule(
  value: string | null,
): value is TranslationModule {
  return (
    value === "pswg" ||
    value === "ministry" ||
    value === "cdc" ||
    value === "cefp" ||
    value === "cdcgpsf"
  );
}

async function getAllTranslations(
  moduleName?: TranslationModule,
  pageKey?: string,
): Promise<Translation[]> {
  const first = await getTranslations({
    page: 1,
    limit: API_PAGE_SIZE,
    module: moduleName,
    pageKey,
  });

  const items = [...first.items];
  const totalPages = Math.max(
    1,
    first.meta.totalPages || 1,
  );

  for (
    let pageNumber = 2;
    pageNumber <= totalPages;
    pageNumber += 1
  ) {
    const next = await getTranslations({
      page: pageNumber,
      limit: API_PAGE_SIZE,
      module: moduleName,
      pageKey,
    });

    items.push(...next.items);
  }

  return items;
}

export function groupTranslationsByPage(
  items: Translation[],
): TranslationPageGroup[] {
  const groupedItems =
    new Map<string, Translation[]>();

  for (const item of items) {
    if (
      !item.page ||
      !isTranslationModule(item.module)
    ) {
      continue;
    }

    /*
     * A normal Page is one group by module + page.
     * For legacy sidebar parent rows, keep independent group.* labels separate.
     */
    const key =
      item.page === "sidebar" &&
      item.translationKey.startsWith("group.")
        ? `${item.module}::${item.page}::${item.translationKey}`
        : `${item.module}::${item.page}`;

    const current =
      groupedItems.get(key) ?? [];

    current.push(item);
    groupedItems.set(key, current);
  }

  const groups: TranslationPageGroup[] = [];

  for (const pageItems of groupedItems.values()) {
    const first = pageItems[0];

    if (!first) {
      continue;
    }

    const page = first.page;
    const moduleName = first.module;

    if (
      !page ||
      !isTranslationModule(moduleName)
    ) {
      continue;
    }

    const representative =
      pageItems.find(
        (item) =>
          item.translationKey === "title",
      ) ??
      pageItems.find(
        (item) =>
          item.translationKey.startsWith("group."),
      ) ??
      pageItems.find(
        (item) =>
          item.translationKey === "subtitle",
      ) ??
      first;

    const activeCount = pageItems.filter(
      (item) => item.isActive,
    ).length;

    const inactiveCount =
      pageItems.length - activeCount;

    const createdAt = pageItems.reduce(
      (earliest, item) =>
        new Date(item.createdAt).getTime() <
        new Date(earliest).getTime()
          ? item.createdAt
          : earliest,
      first.createdAt,
    );

    const updatedAt = pageItems.reduce(
      (latest, item) =>
        new Date(item.updatedAt).getTime() >
        new Date(latest).getTime()
          ? item.updatedAt
          : latest,
      first.updatedAt,
    );

    groups.push({
      id: representative.id,
      module: moduleName,
      page,
      // null explicitly identifies a root page. A label may arrive before
      // its title and point back to that title; borrowing that parent would
      // make the page its own child and hide it from root pagination.
      parentId: representative.parentId ?? null,
      translationKey:
        page === "sidebar"
          ? representative.translationKey
          : undefined,
      englishText:
        representative.englishText,
      khmerText:
        representative.khmerText,
      isActive:
        representative.isActive,
      labelCount:
        pageItems.length,
      activeCount,
      inactiveCount,
      createdAt,
      updatedAt,
    });
  }

  return groups.sort((a, b) => {
    const moduleCompare =
      a.module.localeCompare(b.module);

    if (moduleCompare !== 0) {
      return moduleCompare;
    }

    const parentCompare =
      (a.parentId ?? 0) -
      (b.parentId ?? 0);

    if (parentCompare !== 0) {
      return parentCompare;
    }

    return a.englishText.localeCompare(
      b.englishText,
    );
  });
}

export function useTranslationPageGroups() {
  const [
    allGroups,
    setAllGroups,
  ] = useState<
    TranslationPageGroup[]
  >([]);

  const [page, setPage] =
    useState(1);

  const [search, setSearch] =
    useState("");

  const [
    moduleFilter,
    setModuleFilter,
  ] =
    useState<TranslationModuleFilter>(
      "all",
    );

  const [loading, setLoading] =
    useState(true);

  const [error, setError] =
    useState("");

  const loadGroups =
    useCallback(async () => {
      setLoading(true);
      setError("");

      try {
        const translations =
          await getAllTranslations();

        setAllGroups(
          groupTranslationsByPage(
            translations,
          ),
        );
      } catch (err) {
        setError(
          err instanceof Error
            ? err.message
            : "Unable to load translation pages.",
        );
      } finally {
        setLoading(false);
      }
    }, []);

  useEffect(() => {
    const timer =
      window.setTimeout(() => {
        void loadGroups();
      }, 0);

    return () => {
      window.clearTimeout(timer);
    };
  }, [loadGroups]);

  const filteredGroups =
    useMemo(() => {
      const scopedGroups = filterTranslationPageModules(allGroups, moduleFilter);
      const keyword =
        search.trim().toLowerCase();

      if (!keyword) {
        return scopedGroups;
      }

      /*
       * If a child matches, keep its parent too,
       * so the tree stays understandable.
       */
      const directMatches =
        new Set<number>();

      for (const group of scopedGroups) {
        if (
          group.page
            .toLowerCase()
            .includes(keyword) ||
          group.module
            .toLowerCase()
            .includes(keyword) ||
          group.englishText
            .toLowerCase()
            .includes(keyword) ||
          group.khmerText
            .toLowerCase()
            .includes(keyword) ||
          group.translationKey
            ?.toLowerCase()
            .includes(keyword)
        ) {
          directMatches.add(group.id);
        }
      }

      let changed = true;

      while (changed) {
        changed = false;

        for (const group of scopedGroups) {
          if (
            directMatches.has(group.id) &&
            group.parentId &&
            !directMatches.has(group.parentId)
          ) {
            directMatches.add(
              group.parentId,
            );
            changed = true;
          }
        }
      }

      return scopedGroups.filter(
        (group) =>
          directMatches.has(group.id),
      );
    }, [allGroups, search, moduleFilter]);

  /*
   * Pagination is for ROOT pages only.
   * Children are rendered below their root when expanded.
   */
  const rootGroups =
    filteredGroups.filter(
      (group) =>
        group.parentId === null,
    );

  const total = rootGroups.length;

  const totalPages = Math.max(
    1,
    Math.ceil(total / PAGE_SIZE),
  );

  const safePage = Math.min(
    page,
    totalPages,
  );

  const startIndex =
    (safePage - 1) * PAGE_SIZE;

  const items = rootGroups.slice(
    startIndex,
    startIndex + PAGE_SIZE,
  );

  const meta: TranslationMeta = {
    ...EMPTY_META,
    page: safePage,
    total,
    totalPages,
    hasNextPage:
      safePage < totalPages,
    hasPreviousPage:
      safePage > 1,
  };

  const loadPageLabels =
    useCallback(
      async (
        moduleName: TranslationModule,
        pageKey: string,
      ) =>
        getAllTranslations(
          moduleName,
          pageKey,
        ),
      [],
    );

  const resetFilters = () => {
    setSearch("");
    setModuleFilter("all");
    setPage(1);
  };

  return {
    /*
     * Root rows for current pagination page.
     */
    items,

    /*
     * Full filtered tree source.
     * UI uses parentId to find children recursively.
     */
    allItems: filteredGroups,

    meta,
    search,
    moduleFilter,
    loading,
    error,

    setPage,
    setSearch,
    setModuleFilter,
    setError,

    loadPageLabels,
    reload: loadGroups,
    resetFilters,
  };
}
