import * as git from '../lib/git.js'
import * as branch from '../lib/branch.js'
import * as config from '../lib/config.js'
import * as worktree from '../lib/worktree.js'
import * as version from '../lib/version.js'
import type { FinishResult, FinishOptions } from './types.js'

export async function execute(
  opts: FinishOptions,
  cwd?: string,
): Promise<FinishResult> {
  try {
    // Get current or specified branch
    let currentBranch = opts.branch || await git.getCurrentBranch(cwd)

    // Detect type
    const branchType = branch.detectBranchType(currentBranch)

    // Block if main/develop/other
    if (branchType === 'main' || branchType === 'develop' || branchType === 'other') {
      return {
        success: false,
        branch: currentBranch,
        branchType: 'feature',
        error: `Cannot finish ${branchType} branch`,
      }
    }

    // Read config
    const cfg = await config.readConfigForPlatform()

    // Verify PR is merged
    const isMerged = await git.isMerged(currentBranch, cfg.git.branches.main, cwd)
    if (!isMerged) {
      return {
        success: false,
        branch: currentBranch,
        branchType: branchType as 'feature' | 'release' | 'hotfix',
        error: `Branch ${currentBranch} is not merged into ${cfg.git.branches.main}`,
      }
    }

    let tag: string | undefined
    let mergedBack = false
    let versionBumped = false

    // For release/hotfix: tag on main, merge-back to develop, bump version
    if (branchType === 'release' || branchType === 'hotfix') {
      // Detect version from branch name
      const versionMatch = currentBranch.match(/(?:release|hotfix)\/(.+)/)
      if (versionMatch) {
        const versionStr = versionMatch[1]
        const tagName = `${cfg.versioning.tagPrefix}${versionStr}`
        tag = tagName

        // Create and push tag
        const tagMessage = `Release ${versionStr} (${branchType})`
        await git.createTag(tagName, tagMessage, cwd)
        await git.pushTag(tagName, cwd)

        // Merge-back to develop if not feature
        const developBranch = cfg.git.branches.develop
        const isDevMerged = await git.isMerged(currentBranch, developBranch, cwd)

        if (!isDevMerged) {
          // Checkout develop, merge with no-ff
          await git.checkout(developBranch, cwd)
          await git.mergeNoFf(currentBranch, `Merge ${currentBranch} back to ${developBranch}`, cwd)
          await git.push(developBranch, cwd)
          mergedBack = true
        }

        // Bump version in source files
        const projDir = cfg.repository.rootFolder || cwd || process.cwd()
        const bumpType = version.getBumpType(branchType)
        const newVersion = version.bumpVersion(cfg.versioning.current, bumpType)
        await version.updateVersionSources(projDir, newVersion, cfg.versioning.sources)
        versionBumped = true
      }
    }

    // Cleanup worktree if enabled
    let worktreeCleaned = false
    if (cfg.worktrees.enabled) {
      const wtPath = worktree.getWorktreePath(currentBranch, cfg)
      if (wtPath) {
        try {
          await worktree.removeWorktree(wtPath, cwd)
          worktreeCleaned = true
        } catch {
          // Ignore worktree cleanup errors
        }
      }
    }

    // Delete branch locally and remotely
    try {
      await git.deleteBranch(currentBranch, false, false, cwd)
    } catch {
      // Ignore local deletion errors
    }

    try {
      await git.deleteBranch(currentBranch, true, false, cwd)
    } catch {
      // Ignore remote deletion errors
    }

    return {
      success: true,
      branch: currentBranch,
      branchType: branchType as 'feature' | 'release' | 'hotfix',
      tag,
      mergedBack,
      versionBumped,
      worktreeCleaned,
    }
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err)
    return {
      success: false,
      branch: opts.branch || '',
      branchType: 'feature',
      error: message,
    }
  }
}
