import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';

export type CategoryNode = {
  id: number;
  name: string;
  parentId: number | null;
  children: CategoryNode[];
};

export type FlatCategory = {
  id: number;
  name: string;
  path: string;
};

@Injectable()
export class CategoriesService {
  constructor(private readonly prisma: PrismaService) {}

  async findAll() {
    return this.prisma.category.findMany({ orderBy: { name: 'asc' } });
  }

  async findTree(): Promise<CategoryNode[]> {
    const all = await this.prisma.category.findMany({ orderBy: { name: 'asc' } });
    const map = new Map<number, CategoryNode>();
    all.forEach((c) => map.set(c.id, { ...c, children: [] }));
    const roots: CategoryNode[] = [];
    map.forEach((node) => {
      if (node.parentId === null) {
        roots.push(node);
      } else {
        map.get(node.parentId)?.children.push(node);
      }
    });
    return roots;
  }

  async findFlattened(): Promise<FlatCategory[]> {
    const all = await this.prisma.category.findMany({ orderBy: { name: 'asc' } });

    const byId = new Map<number, { id: number; name: string; parentId: number | null }>();
    all.forEach((c) => byId.set(c.id, c));

    const pathCache = new Map<number, string>();

    const buildPath = (id: number): string => {
      const cached = pathCache.get(id);
      if (cached) return cached;

      const current = byId.get(id);
      if (!current) return '';

      const path = current.parentId == null
        ? current.name
        : `${buildPath(current.parentId)} > ${current.name}`;

      pathCache.set(id, path);
      return path;
    };

    return all.map((c) => ({
      id: c.id,
      name: c.name,
      path: buildPath(c.id),
    }));
  }
}
