#!/usr/bin/env ruby
# encoding: UTF-8
# frozen_string_literal: true

# exec-worktree (intent 213, group 2) - finish an intent's code worktree: an order
# precondition, then Worktree.finish (delivered merges + removes, abandoned removes only).
#
# Usage:
#   exec-worktree --store <path> --id <intent_id> --home <plastic_home> \
#                 --disposition delivered|abandoned [--session <session_id>]
#
# --home accepts either spelling: the OS-home level (the PARENT of .plastic) or the
# .plastic directory itself. When the given path's basename is literally .plastic, its
# dirname is used instead. Worktree.finish's home: keyword always wants the OS-home
# level (Worktree.home_from_store, scripts/lib/worktree.rb:90); this script normalizes
# both spellings to that so either caller convention works.
#
# Steps performed:
#   0. Resolve inputs: the intent dir, normalize --home, resolve the calling session
#      (--session, else CLAUDE_CODE_SESSION_ID, else the existing delivery.lock's own
#      recorded owner_session when non-blank, else nil; unlike start-intent, the
#      lock-owner fallback IS used here, matching end-intent's teardown resolution order).
#      Load the bridge (Bridge.read); a nil bridge means there is nothing to finish (exit
#      0, loud: the worktree this intent provisioned, if any, was NOT removed). No
#      worktree.code on the bridge means nothing was provisioned (exit 0).
#   1. The order precondition (delivered only): calls the EXISTING
#      Bridge.code_gate_decision predicate exactly as it exists. On an auto bridge that
#      has not reached How, this BLOCKS (exit 2). Bridge.code_gate_decision returns nil
#      UNCONDITIONALLY on a guided bridge (build.auto != true), so on a guided bridge
#      this precondition is ADVISORY ONLY: it always passes and the run proceeds. This
#      script is NOT the enforcement point either way; the hook layer
#      (scripts/lib/bridge.rb code_gate_decision, wired through scripts/lib/edit_gates.rb)
#      remains the actual gate. See scripts/lib/exec_worktree.rb's module doc for why the
#      auto-only condition is never relaxed and never duplicated here.
#   2. The dirty-worktree guard (delivered only): git status --porcelain on the code
#      worktree. Not clean, or the check itself fails, fails CLOSED (exit 3), mirroring
#      end-intent's dirty-worktree handling. abandoned skips this guard entirely: the
#      branch survives and can be reclaimed, so a dirty worktree is not a reason to
#      refuse.
#   3. Finish: Worktree.finish(bridge_data, home:, runner:, merge: disposition ==
#      "delivered"). Worktree.finish is fail-open and never raises, so failure is
#      detected by checking, for a delivered disposition only, whether the worktree
#      directory still exists on disk afterward (release removes it on success).
#
# No test suite is run by this script, in any form. verify-intent owns test execution;
# one concern per script (spec D8).
#
# Exit codes:
#   0  finished (merged or removed per disposition), or nothing to finish (no bridge
#      resolved, or no code worktree recorded on the bridge)
#   1  usage or path-resolution failure
#   2  the order precondition blocked a delivered disposition (auto bridge, How not
#      reached)
#   3  the worktree is not clean, or the merge/removal did not complete (delivered only)
#   4  lock or session resolution failure

require_relative "lib/exec_worktree"

def parse_args(argv)
  opts = { store: nil, id: nil, home: nil, disposition: nil, session: nil }
  i = 0
  while i < argv.length
    arg = argv[i]
    case arg
    when "--store"       then opts[:store] = argv[i += 1]
    when "--id"          then opts[:id] = argv[i += 1]
    when "--home"        then opts[:home] = argv[i += 1]
    when "--disposition" then opts[:disposition] = argv[i += 1]
    when "--session"     then opts[:session] = argv[i += 1]
    else
      usage_abort("unknown argument #{arg.inspect}")
    end
    i += 1
  end
  opts
end

def usage
  "usage: exec-worktree --store <store_path> --id <intent_id> --home <plastic_home> " \
    "--disposition delivered|abandoned [--session <session_id>]"
end

def usage_abort(message)
  warn "exec-worktree: #{message}"
  warn usage
  exit 1
end

def main(argv)
  opts = parse_args(argv)

  result = ExecWorktree.run(
    store: opts[:store], id: opts[:id], home: opts[:home], disposition: opts[:disposition],
    session: opts[:session], env_session: ENV["CLAUDE_CODE_SESSION_ID"]
  )

  Array(result[:stderr]).each { |line| warn line }
  warn usage if result[:exit_code] == ExecWorktree::EXIT_USAGE
  Array(result[:stdout]).each { |line| puts line }
  exit result[:exit_code]
end

main(ARGV) if $PROGRAM_NAME == __FILE__
