import { join } from 'node:path'
import { readdirSync, Dirent } from 'node:fs'

export type Ressource = {
  id: number
  name: string
  path: string
  depth: number
  isDir: boolean
  isVisible?: boolean
  extension?: string
  isOpen?: boolean // Only valide for folder;
  childrenIds?: number[]
}

export type Ressources = Ressource[]

export type ConfigT = {
  indent: number
  defaultDepth: number
  defaultRes: Ressource
}

export type StateT = {
  config: ConfigT
  ressources: Ressources
}

export const PIJUL_DIR = '.pijul'

export function getExtension(name: string): string {
  const splitted = name.split('.')
  return splitted.at(-1)!
}

export function getParent(path: string): string {
  return path.split('/').at(-1) as string
}

export const cmpDirent = (a: Dirent, b: Dirent): 0 | 1 | -1 =>
  !a.isDirectory() && b.isDirectory()
    ? -1
    : a.isDirectory() && !b.isDirectory()
    ? 1
    : 0

export const cmpRessources = (a: Ressource, b: Ressource): 0 | 1 | -1 =>
  a.depth > b.depth
    ? 1
    : a.depth < b.depth
    ? -1
    : a.isDir && !b.isDir
    ? -1
    : !a.isDir && b.isDir
    ? 1
    : ((s1: string, s2: string) => (s1 === s2 ? 0 : s1 > s2 ? 1 : -1))(
        a.name,
        b.name
      )

export function getRessources(path = 'repo') {
  const ressources: Ressources = []
  const collectRessources = (path: string, depth = 1, len = 0) => {
    const children = readdirSync(path, { withFileTypes: true })
      .filter((dirent) => dirent.name !== PIJUL_DIR)
      .sort(cmpDirent)
      .map((dirent, index) => {
        return {
          id: len === 0 ? index + 1 : len + index,
          ...(dirent.isDirectory()
            ? { extension: getExtension(dirent.name) }
            : null),
          name: dirent.name,
          path: join(path, dirent.name),
          depth,
          isDir: dirent.isDirectory(),
        }
      })

    if (len !== 0) {
      const childrenIds = children.map((ressource) => ressource.id)
      ressources.forEach((ressource, index, ressources) => {
        if (ressource.isDir && ressource.path === path) {
          ressources[index] = {
            ...ressource,
            childrenIds,
          }
        }
      })
    }

    ressources.push(...children)

    children.forEach((ressource) => {
      if (ressource.isDir) {
        collectRessources(ressource.path, depth + 1, ressources.length)
      }
    })
  }

  collectRessources(path)
  return ressources
}

export const transformRessources = (ressources: Ressources): Ressources =>
  ressources.sort(cmpRessources).map((ressource) => ({
    ...ressource,
    ...(ressource.depth > 1 ? { isVisible: false } : { isVisible: true }),
    ...(ressource.depth > 1 ? { isOpen: false } : { isVisible: true }),
  }))