import { MAX_ARTICLES_DEPTH } from '@composed-components/LibrariesSidebar/constants';
import {
  EMPTY_SIDEBAR_MODEL,
  type SidebarArticleLike,
  type SidebarArticleTree,
  type SidebarModel,
  type SidebarNode,
  type SidebarNodeFilterContext,
  type SidebarNodePredicate,
} from '@composed-components/LibrariesSidebar/types/model';
import {
  buildDepthMap,
  flattenTree,
  sortByPosition,
} from '@composed-components/LibrariesSidebar/utils/tree';

const toSidebarNode = (
  article: SidebarArticleLike,
  depth: number,
  parentId: number | null,
  childCount: number,
): SidebarNode => ({
  id: article.id,
  parentId,
  position: article.position ?? 0,
  title: article.title,
  icon: article.icon,
  status: article.status,
  childCount,
  depth,
  isEditor: article.isEditor,
});

/** Root list: GET /knowledge-libraries → PaginatedResponse items. */
export const adaptFromRootArticles = (
  articles: SidebarArticleLike[],
): SidebarModel => ({
  headerTitle: '',
  nodes: sortByPosition(articles).map(article =>
    toSidebarNode(article, 1, null, article.children?.length ?? 0),
  ),
});

/** Nested tree: GET /knowledge-libraries/:id/children-tree → ArticleTree. */
export const adaptFromChildrenTree = (
  tree: SidebarArticleTree | undefined | null,
  viewParentId?: number,
): SidebarModel => {
  if (!tree) return EMPTY_SIDEBAR_MODEL;

  const depthMap = buildDepthMap(tree);
  const fallbackParentId = viewParentId ?? tree.id;

  const nodes = sortByPosition(flattenTree(tree)).map(article =>
    toSidebarNode(
      article,
      depthMap.get(article.id) ?? 1,
      article.parentId ?? fallbackParentId,
      article.children?.length ?? 0,
    ),
  );

  return { headerTitle: tree.title, nodes };
};

/** Pick root vs nested model after both queries have been adapted. */
export const resolveSidebarModel = (
  isRoot: boolean,
  rootArticles: SidebarArticleLike[],
  childrenModel?: SidebarModel | null,
): SidebarModel =>
  isRoot
    ? adaptFromRootArticles(rootArticles)
    : (childrenModel ?? EMPTY_SIDEBAR_MODEL);

/** Recompute direct-child counts from the flat node list (e.g. after filtering). */
export const recalculateChildCounts = (model: SidebarModel): SidebarModel => {
  const nodeIds = new Set(model.nodes.map(node => node.id));
  const childCounts = new Map<number, number>();

  for (const node of model.nodes) {
    if (node.parentId != null && nodeIds.has(node.parentId)) {
      childCounts.set(node.parentId, (childCounts.get(node.parentId) ?? 0) + 1);
    }
  }

  return {
    headerTitle: model.headerTitle,
    nodes: model.nodes.map(node => ({
      ...node,
      childCount: childCounts.get(node.id) ?? 0,
    })),
  };
};

/** Filter nodes with a consumer-provided predicate and refresh child counts. */
export const applySidebarNodeFilter = (
  model: SidebarModel,
  predicate: SidebarNodePredicate,
  context: SidebarNodeFilterContext,
): SidebarModel =>
  recalculateChildCounts({
    headerTitle: model.headerTitle,
    nodes: model.nodes.filter(node => predicate(node, context)),
  });

export { MAX_ARTICLES_DEPTH };
