import { type Repository } from "./dataTypes.ts"

let cachedFlatFiles: Array<FlatFileEntry> | null = null

export type FlatFileEntry = {
  file: string,
  refName: string,
  repoName: string,
  type: 'branch' | 'tag',
  isDirectory: boolean,
}

const dirsFromRefFileList: (
  ref: Repository['tags'][0],
  repoName: string,
  refType: 'branch' | 'tag'
) => Array<FlatFileEntry> = (ref, repoName, refType) => {
  const filesAndDirs = new Set<string>()

  for (const file of ref.fileList) {
    const fileParts = file.split('/')

    // Iterate through fileParts except for the last part, which will be
    // the file name. Since we just want dirs here, we can ignore that.
    const filePartsWithoutEnd = fileParts.slice(0, fileParts.length - 1)
    for (const [index, _val] of filePartsWithoutEnd.entries()) {
      const path = fileParts.slice(0, filePartsWithoutEnd.length - index).join('/')
      if (filesAndDirs.has(path)) {
        break
      } else {
        filesAndDirs.add(path)
      }
    }
  }

  return Array.from(filesAndDirs).map((file) => {
    return {
      file,
      refName: ref.name,
      repoName: repoName,
      type: refType,
      isDirectory: true,
    }
  })
}

const filesFromRefFileList: (
  ref: Repository['tags'][0],
  repoName: string,
  refType: 'branch' | 'tag'
) => Array<FlatFileEntry> = (ref, repoName, refType) => {
  return Array.from(ref.fileList).map((file) => {
    return {
      file,
      refName: ref.name,
      repoName: repoName,
      type: refType,
      isDirectory: false,
    }
  })
}

const flatFiles = (repos: Array<Repository>) : Array<FlatFileEntry> => {
  if (cachedFlatFiles !== null) { return cachedFlatFiles }

  const branches: FlatFileEntry[] = repos.flatMap((repo) => {
    return repo.branches.flatMap(branch => filesFromRefFileList(branch, repo.name, 'branch'))
  })

  const tags: FlatFileEntry[] = repos.flatMap((repo) => {
    return repo.tags.flatMap(tag => filesFromRefFileList(tag, repo.name, 'tag'))
  })

  cachedFlatFiles = [...branches, ...tags]

  return cachedFlatFiles
}

const flatDirectories = (repos: Array<Repository>) : Array<FlatFileEntry> => {
  const branches: FlatFileEntry[] = repos.flatMap((repo) => {
    return repo.branches.flatMap(branch => dirsFromRefFileList(branch, repo.name, 'branch'))
  })

  const tags: FlatFileEntry[] = repos.flatMap((repo) => {
    return repo.tags.flatMap(tag => dirsFromRefFileList(tag, repo.name, 'tag'))
  })

  return [...branches, ...tags]
}

export {
  flatFiles,
  flatDirectories,
}
