/**
 * Shared cleanup primitives for `workleaf merge` and `workleaf delete`.
 *
 * The two commands diverge only in whether they squash-merge first;
 * everything below (stop server, remove worktree, delete branch,
 * release port) is identical.
 */

import * as p from '@clack/prompts'
import { execFileSync } from 'node:child_process'
import { existsSync, rmdirSync } from 'node:fs'
import { dirname } from 'node:path'
import { releasePort } from '../worktree/port.js'
import { findByWorktree, unregister } from '../worktree/serverRegistry.js'
import { dim } from '../cli/intro.js'

/**
 * Send SIGTERM to every dev server registered for this workleaf branch,
 * then unregister them. Best-effort — never throws.
 */
export function stopDevServer(branch) {
  const servers = findByWorktree(branch)
  for (const s of servers) {
    try {
      process.kill(s.pid, 'SIGTERM')
    } catch (err) {
      if (err.code !== 'ESRCH') {
        p.log.warn(`Could not stop pid ${s.pid}: ${err.message}`)
      }
    }
    unregister(s.id)
  }
  return servers.length
}

/**
 * Remove the git worktree directory. Uses --force so uncommitted state
 * in the workleaf doesn't block delete (callers should validate dirty
 * state first). Also tries to remove the now-empty parent group dir
 * (workleafs/<parent>/) for cosmetic cleanliness.
 */
export function removeWorktree(dir, root) {
  if (!existsSync(dir)) return
  try {
    execFileSync('git', ['worktree', 'remove', '--force', dir], { cwd: root, stdio: 'pipe' })
  } catch (err) {
    p.log.warn(`git worktree remove failed: ${err.message}`)
    p.log.info(dim(`  Try: rm -rf ${dir} && git worktree prune`))
  }
  // Try to remove the empty parent group dir (workleafs/<parent>/) — best
  // effort, silently no-ops if the dir still has siblings.
  try {
    rmdirSync(dirname(dir))
  } catch { /* still has siblings or already gone */ }
}

/**
 * Delete the workleaf branch. Uses -D to allow deleting unmerged branches
 * (delete subcommand) — merge subcommand callers may want to verify
 * merge-state first.
 */
export function deleteBranch(branch, root) {
  try {
    execFileSync('git', ['branch', '-D', branch], { cwd: root, stdio: 'pipe' })
  } catch (err) {
    p.log.warn(`git branch -D ${branch} failed: ${err.message}`)
  }
}

/**
 * Full cleanup sequence shared by merge + delete:
 *   1. Stop & unregister dev server(s)
 *   2. Remove the git worktree
 *   3. Delete the branch
 *   4. Release the port assignment
 */
export function cleanupWorkleaf({ branch, dir, root }) {
  const stopped = stopDevServer(branch)
  removeWorktree(dir, root)
  deleteBranch(branch, root)
  releasePort(branch)
  return { stopped }
}

/** Read the current branch of a directory. */
export function currentBranch(cwd) {
  try {
    return execFileSync('git', ['branch', '--show-current'], { cwd, encoding: 'utf8' }).trim()
  } catch {
    return null
  }
}

/** Check for uncommitted state in a worktree. */
export function hasDirtyWorkingTree(cwd) {
  try {
    const out = execFileSync('git', ['status', '--porcelain'], { cwd, encoding: 'utf8' }).trim()
    return out.length > 0
  } catch {
    return false
  }
}
