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

type Commit = ReturnType<Repository['commits']['get']>
type FlatPatchRecord = {
  commit: Commit,
  repoName: string,
  refName: string,
  type: "branch" | "tag",
}

let cachedFlatPatches: Array<FlatPatchRecord> | null = null
let cachedRepoCommits: Array<{
  repoName: string,
  commit: Commit,
}> | null = null

const flatPatches = (repos: Array<Repository>)
  : Array<FlatPatchRecord> => {
  if (cachedFlatPatches !== null) { return cachedFlatPatches }

  const itemsForRef: (
    ref: Repository['tags'][0],
    refType: 'branch' | 'tag',
    repo: Repository
  ) => Array<FlatPatchRecord> = (ref, refType, repo) => {
    const flatPatches: Array<FlatPatchRecord> = []
    let currentCommit: ReturnType<Repository['commits']['get']> | undefined = repo.commits.get(ref.sha)

    while (currentCommit !== undefined) {
      flatPatches.push({
        type: refType,
        commit: currentCommit,
        repoName: repo.name,
        refName: ref.name
      })

      currentCommit = repo.commits.get(currentCommit.parent)
    }

    return flatPatches
  }



  cachedFlatPatches = repos.flatMap((repo) => {
    const branches = repo.branches.flatMap(branch => itemsForRef(branch, 'branch', repo))

    const tags = repo.tags.flatMap(tag => itemsForRef(tag, 'tag', repo))

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

  return cachedFlatPatches
}

const commitsInRepo = (repos: Array<Repository>) : Array<{repoName: string, commit: Commit}> => {
  if (cachedRepoCommits !== null) { return cachedRepoCommits }

  cachedRepoCommits = repos.flatMap((repo) => {
    return Array.from(repo.commits.values()).map((commit) => {
      return {
        repoName: repo.name,
        commit,
      }
    })
  })

  return cachedRepoCommits
}

export {
  flatPatches,
  commitsInRepo,
}
