#!/usr/bin/env ruby
# frozen_string_literal: true
#
# wakeup-poll: one pass of the issue-triggered wakeup poller (ADR-0035).
#
# Reads the global project index (~/.cc-os/projects.json, ADR-0034), and for
# each wakeup-opted-in forgejo:/github: project lists open issues (tea/gh),
# diffs against last-seen state (~/.cc-os/wakeup-state.json), and for each
# NEW issue either spawns a tmux session (ADR-0036) or — the default —
# prints the command it WOULD run. hitl/unlabeled issues are notify-only:
# appended to ~/.cc-os/wakeup-summary.md (pull-only, notification policy v2).
#
# Usage:
#   wakeup-poll             # dry-run: print planned actions, touch no state
#   wakeup-poll --spawn     # actually create tmux sessions + persist state
#
# Fails soft everywhere: missing index, unroutable projects, tea/gh errors,
# and absent tmux each degrade to a printed note, never a crash. The poller
# uses tea/gh's existing logins only and never reads ~/.credentials.
# Pilot only — install no cron around this until ADR-0035 is Accepted.

require "json"
require "open3"
require "shellwords"
require_relative "../lib/backlog"

spawn_mode = ARGV.include?("--spawn")

def note(msg) = puts("wakeup-poll: #{msg}")

def list_issues(kind, slug)
  cmd =
    case kind
    when "forgejo" then ["tea", "issues", "list", "--repo", slug, "--state", "open", "--output", "json"]
    when "github" then ["gh", "issue", "list", "--repo", slug, "--state", "open",
                        "--json", "number,title,labels,body,url"]
    end
  out, err, status = Open3.capture3(*cmd)
  return nil unless status.success?

  rows = JSON.parse(out)
  # Normalize gh's shape to tea's {index, title, labels}.
  rows.map do |r|
    { "index" => (r["index"] || r["number"]).to_s,
      "title" => r["title"],
      "labels" => r["labels"].is_a?(Array) ? r["labels"].map { |l| l["name"] }.join(",") : r["labels"].to_s,
      "body" => r["body"].to_s,
      "url" => r["url"].to_s }
  end
rescue StandardError => e
  warn "wakeup-poll: #{slug}: #{e.class}: #{e.message}"
  nil
end

index = Backlog::ProjectIndex.new
projects = index.all
if projects.empty?
  note "project index empty or unreadable — nothing to do"
  exit 0
end

config_reader = lambda do |path|
  file = File.join(path, ".cc-os", "config")
  File.exist?(file) ? File.read(file) : ""
rescue StandardError
  ""
end

eligible = Backlog::Wakeup.eligible_projects(projects, config_reader: config_reader)
skipped = projects.keys - eligible.map { |p| p[:path] }
skipped.each { |path| note "skip #{path} (#{projects[path]['tracker'] || 'no tracker'}: not a wakeup-eligible forgejo/github project, or wakeup=true not set)" }

if eligible.empty?
  note "no opted-in forgejo/github projects — nothing to do"
  exit 0
end

state = Backlog::Wakeup::State.new
summary_path = File.join(File.dirname(Backlog::Wakeup::State.default_path), "wakeup-summary.md")

eligible.each do |project|
  issues = list_issues(project[:tracker_kind], project[:repo_slug])
  if issues.nil?
    note "#{project[:repo_slug]}: issue listing failed (is #{project[:tracker_kind] == 'forgejo' ? 'tea' : 'gh'} logged in?) — skipping"
    next
  end

  last_seen = state.last_seen(project[:repo_slug])
  if last_seen.nil?
    top = Backlog::Wakeup.highest_index(issues)
    note "#{project[:repo_slug]}: first scan — baselining at ##{top}, waking nothing"
    state.record(project[:repo_slug], top) if spawn_mode
    next
  end

  fresh = Backlog::Wakeup.new_issues(issues, last_seen)
  note "#{project[:repo_slug]}: #{fresh.size} new issue(s) since ##{last_seen}" if fresh.any?

  fresh.each do |issue|
    tier = Backlog::Wakeup.tier(issue["labels"])
    if tier == :notify
      line = "- #{Time.now.strftime('%Y-%m-%d')} #{project[:repo_slug]}##{issue['index']} (#{tier}): #{issue['title']}"
      if spawn_mode
        File.open(summary_path, "a") { |f| f.puts(line) }
        note "notify-only -> appended to #{summary_path}"
      else
        note "would append to #{summary_path}: #{line}"
      end
      next
    end

    prompt = Backlog::Wakeup.session_prompt(
      issue: issue, tier: tier,
      url: issue["url"].empty? ? "#{project[:tracker_kind]}:#{project[:repo_slug]}##{issue['index']}" : issue["url"]
    )
    cmd = Backlog::Wakeup.tmux_command(
      project: project[:name], path: project[:path],
      issue_index: issue["index"], prompt: prompt
    )
    if spawn_mode
      ok = system(*cmd)
      note ok ? "spawned #{cmd[4]}" : "tmux spawn failed for #{cmd[4]} (is tmux installed?)"
    else
      note "would run: #{cmd.shelljoin}"
    end
  end

  state.record(project[:repo_slug], Backlog::Wakeup.highest_index(issues, last_seen)) if spawn_mode
end

note "dry-run complete — no state written, no sessions spawned (use --spawn)" unless spawn_mode
