import { describe, expect, it } from 'vitest'
import { join, resolve } from 'path'
import {
  repoRootConfigFromCommonDir,
  developWorktreePath,
  decideConfigResolution,
} from '../config.js'

describe('repoRootConfigFromCommonDir', () => {
  // The config lives at <repo-root>/.gitflow/config.json, where the repo root is
  // the PARENT of the git common dir. Fixtures are made absolute via resolve() so
  // the assertion is OS-independent (Windows drive letters included).

  it('points to <root>/.gitflow/config.json for an absolute common dir, from any worktree', () => {
    const root = resolve('fixture-proj')
    const commonDir = join(root, '.git')
    // Same answer whether we ask from main, develop or a feature worktree.
    for (const wt of ['main', 'develop', join('features', 'feat-x')]) {
      expect(repoRootConfigFromCommonDir(commonDir, join(root, wt))).toBe(
        join(root, '.gitflow', 'config.json'),
      )
    }
  })

  it('resolves a RELATIVE common dir (git can return ".git") against cwd', () => {
    const cwd = resolve('fixture-rel')
    // dirname(resolve(cwd, '.git')) === cwd → <cwd>/.gitflow/config.json
    expect(repoRootConfigFromCommonDir('.git', cwd)).toBe(join(cwd, '.gitflow', 'config.json'))
  })
})

describe('developWorktreePath', () => {
  const block = (path: string, branch?: string) =>
    `worktree ${path}\nHEAD 0000000\n${branch ? `branch refs/heads/${branch}` : 'detached'}\n`

  it('returns the path of the worktree checked out on develop', () => {
    const porcelain = [block('/repo/main', 'main'), block('/repo/develop', 'develop')].join('\n')
    expect(developWorktreePath(porcelain)).toBe('/repo/develop')
  })

  it('finds develop even amid feature/release worktrees', () => {
    const porcelain = [
      block('/repo/main', 'main'),
      block('/repo/features/feat-x', 'feature/feat-x'),
      block('/repo/develop', 'develop'),
      block('/repo/releases/1.2.0', 'release/1.2.0'),
    ].join('\n')
    expect(developWorktreePath(porcelain)).toBe('/repo/develop')
  })

  it('returns null when no worktree is on develop', () => {
    const porcelain = [block('/repo/main', 'main'), block('/repo/hotfix', 'hotfix/x')].join('\n')
    expect(developWorktreePath(porcelain)).toBeNull()
  })

  it('ignores a detached worktree (no branch line)', () => {
    expect(developWorktreePath(block('/repo/detached'))).toBeNull()
  })
})

describe('decideConfigResolution', () => {
  const ROOT = '/repo/.gitflow/config.json'
  const LEGACY = '/repo/develop/.claude/gitflow/config.json'

  it('reads the root config when it already exists (canonical wins)', () => {
    expect(decideConfigResolution({ rootPath: ROOT, rootExists: true, legacyPath: LEGACY })).toEqual({
      action: 'root',
      path: ROOT,
    })
  })

  it('migrates legacy → root when only the legacy config exists', () => {
    expect(decideConfigResolution({ rootPath: ROOT, rootExists: false, legacyPath: LEGACY })).toEqual({
      action: 'migrate',
      from: LEGACY,
      to: ROOT,
    })
  })

  it('falls back to the legacy path when the root is not computable', () => {
    expect(decideConfigResolution({ rootPath: null, rootExists: false, legacyPath: LEGACY })).toEqual({
      action: 'legacy',
      path: LEGACY,
    })
  })

  it('returns none when neither root nor legacy config is found', () => {
    expect(decideConfigResolution({ rootPath: ROOT, rootExists: false, legacyPath: null })).toEqual({
      action: 'none',
    })
  })
})
