import { describe, expect, it } from 'vitest'
import {
  assertBranchTarget,
  getBaseBranch,
  getTargetBranch,
  normalizeNameForType,
  normalizeReleaseName,
  buildFullBranchName,
} from '../branch.js'
import type { GitFlowConfig } from '../types.js'

function cfg(main = 'main', develop = 'develop'): GitFlowConfig {
  return {
    git: {
      branches: { main, develop },
      prefixes: { feature: 'feature/', release: 'release/', hotfix: 'hotfix/' },
    },
  } as unknown as GitFlowConfig
}

describe('getBaseBranch', () => {
  it('release branches FROM develop (4.x rule)', () => {
    expect(getBaseBranch('release', cfg())).toBe('develop')
  })
  it('feature from develop, hotfix from main', () => {
    expect(getBaseBranch('feature', cfg())).toBe('develop')
    expect(getBaseBranch('hotfix', cfg())).toBe('main')
  })
})

describe('getTargetBranch', () => {
  it('feature → develop, release/hotfix → main', () => {
    expect(getTargetBranch('feature', cfg())).toBe('develop')
    expect(getTargetBranch('release', cfg())).toBe('main')
    expect(getTargetBranch('hotfix', cfg())).toBe('main')
  })
})

describe('assertBranchTarget — feature→main guard (incident #451)', () => {
  it('throws when a feature targets main', () => {
    expect(() => assertBranchTarget('feature', 'main', cfg())).toThrow()
  })
  it('throws when a feature targets master', () => {
    expect(() => assertBranchTarget('feature', 'master', cfg('master'))).toThrow()
  })
  it('throws when develop is empty (the #451 root cause)', () => {
    expect(() => assertBranchTarget('feature', '', cfg('main', ''))).toThrow()
  })
  it('throws when develop === main', () => {
    expect(() => assertBranchTarget('feature', 'main', cfg('main', 'main'))).toThrow()
  })
  it('allows a feature → develop', () => {
    expect(() => assertBranchTarget('feature', 'develop', cfg())).not.toThrow()
  })
  it('allows release/hotfix → main', () => {
    expect(() => assertBranchTarget('release', 'main', cfg())).not.toThrow()
    expect(() => assertBranchTarget('hotfix', 'main', cfg())).not.toThrow()
  })
})

describe('per-type name normalization', () => {
  it('keeps version dots for release/hotfix (3.53.0 stays 3.53.0)', () => {
    expect(normalizeNameForType('3.53.0', 'release')).toBe('3.53.0')
    expect(normalizeNameForType('3.53.1', 'hotfix')).toBe('3.53.1')
    expect(normalizeReleaseName('  v1.20.0 ')).toBe('v1.20.0')
  })
  it('kebab-cases feature names (dots/accents stripped)', () => {
    expect(normalizeNameForType('Mon Idée!', 'feature')).toBe('mon-idee')
  })
  it('builds the full branch with the right prefix and dots intact', () => {
    expect(buildFullBranchName(normalizeNameForType('3.53.0', 'release'), 'release', cfg())).toBe('release/3.53.0')
    expect(buildFullBranchName(normalizeNameForType('User Auth', 'feature'), 'feature', cfg())).toBe('feature/user-auth')
  })
})
