/**
 * Workleaf path helpers.
 *
 * A workleaf is an ephemeral sub-worktree owned by a parent worktree (or
 * main). It lives at:
 *
 *   <repo-root>/workleafs/<parent>/workleaf--<slug>/
 *
 * The parent name is encoded in the path — no metadata file is needed.
 * Workleaves cannot be nested: spawning a workleaf from inside another
 * workleaf is refused at the CLI layer using `detectWorkleafContext`.
 *
 * Branch naming convention is `<parent>--workleaf--<slug>` so the branch
 * is self-describing in `git branch` output even without spatial context.
 *
 * This module is intentionally pure and side-effect-free so it can be
 * unit-tested without touching the filesystem (apart from the listing
 * helper, which obviously must read disk).
 */

import { existsSync, readdirSync, realpathSync } from 'fs'
import { join } from 'path'
import { repoRoot, slugify } from '../worktree/port.js'

/** Literal prefix every workleaf directory and branch slug carries. */
export const WORKLEAF_PREFIX = 'workleaf--'

/** Branch convention: `<parent>--workleaf--<slug>`. */
export const WORKLEAF_BRANCH_SEPARATOR = '--workleaf--'

/**
 * Build the absolute on-disk path for a workleaf.
 *
 * @param {string} parent — parent worktree name (e.g. 'main' or '4.3.0')
 * @param {string} name — user-supplied workleaf name (will be slugified)
 * @param {string} [cwd] — for tests; falls back to process.cwd()
 * @returns {string} absolute path
 */
export function workleafDir(parent, name, cwd) {
  const root = repoRoot(cwd)
  const slug = slugify(name)
  return join(root, 'workleafs', parent, WORKLEAF_PREFIX + slug)
}

/**
 * Compose the git branch name for a workleaf.
 *
 * @param {string} parent
 * @param {string} name
 * @returns {string} e.g. '4.3.0--workleaf--quick-fix'
 */
export function workleafBranchName(parent, name) {
  const slug = slugify(name)
  return `${parent}${WORKLEAF_BRANCH_SEPARATOR}${slug}`
}

/**
 * Inverse of {@link workleafBranchName}. Splits `parent--workleaf--slug`
 * into its parts. Uses the LAST occurrence of `--workleaf--` so the
 * function survives parent names that contain `--workleaf--` literally
 * (unlikely, but cheap to handle).
 *
 * Returns null if the input is not a workleaf branch.
 */
export function parentOfWorkleaf(branchName) {
  if (typeof branchName !== 'string') return null
  const idx = branchName.lastIndexOf(WORKLEAF_BRANCH_SEPARATOR)
  if (idx <= 0) return null
  const parent = branchName.slice(0, idx)
  const slug = branchName.slice(idx + WORKLEAF_BRANCH_SEPARATOR.length)
  if (!parent || !slug) return null
  return { parent, slug }
}

/**
 * Detect whether the given cwd is inside a workleaf, and if so, which
 * parent and slug it belongs to.
 *
 * Returns:
 *   { inWorkleaf: true,  parent, slug, branch, dir, root } when inside
 *   { inWorkleaf: false }                                  when outside
 *
 * Uses realpathSync to resolve symlinks before pattern-matching — same
 * convention as `worktree/port.js`. Falls back to the raw cwd if the
 * path does not exist on disk yet (e.g. during dry-run tests).
 */
export function detectWorkleafContext(cwd = process.cwd()) {
  let realCwd
  try {
    realCwd = realpathSync(cwd)
  } catch {
    realCwd = cwd
  }

  // Match <root>/workleafs/<parent>/workleaf--<slug> (anywhere within it).
  // Capture groups: 1=root, 2=parent, 3=slug.
  const re = new RegExp(`^(.+)[/\\\\]workleafs[/\\\\]([^/\\\\]+)[/\\\\]${WORKLEAF_PREFIX}([^/\\\\]+)`)
  const m = realCwd.match(re)
  if (!m) return { inWorkleaf: false }

  const [, root, parent, slug] = m
  return {
    inWorkleaf: true,
    parent,
    slug,
    branch: workleafBranchName(parent, slug),
    dir: join(root, 'workleafs', parent, WORKLEAF_PREFIX + slug),
    root,
  }
}

/**
 * Enumerate every workleaf on disk under <repoRoot>/workleafs/, grouped
 * by parent. Skips entries that don't look like real git worktrees
 * (must contain a `.git` file at the workleaf root).
 *
 * @param {string} [cwd]
 * @returns {Array<{ parent: string, slug: string, branch: string, dir: string }>}
 */
export function listWorkleafs(cwd) {
  const root = repoRoot(cwd)
  const base = join(root, 'workleafs')
  if (!existsSync(base)) return []

  const out = []
  for (const parentEntry of readdirSync(base, { withFileTypes: true })) {
    if (!parentEntry.isDirectory()) continue
    const parent = parentEntry.name
    const parentDir = join(base, parent)
    for (const child of readdirSync(parentDir, { withFileTypes: true })) {
      if (!child.isDirectory()) continue
      if (!child.name.startsWith(WORKLEAF_PREFIX)) continue
      const dir = join(parentDir, child.name)
      // A worktree-managed directory has a `.git` file (not dir) inside.
      if (!existsSync(join(dir, '.git'))) continue
      const slug = child.name.slice(WORKLEAF_PREFIX.length)
      out.push({
        parent,
        slug,
        branch: workleafBranchName(parent, slug),
        dir,
      })
    }
  }
  return out
}
