#!/usr/bin/env nu
# reflection/modules/backlog.nu — backlog management commands.

use env.nu *
use store.nu [daemon-export-safe]

export def "backlog list" [
  --status: string = "",
  --kind:   string = "",
  --fmt:    string = "",
] {
  let f     = if ($fmt | is-not-empty) { $fmt } else { "table" }
  let items = (backlog-load)
  let rows  = if ($status | is-not-empty) {
    $items | where status == $status
  } else if ($kind | is-not-empty) {
    $items | where kind == $kind
  } else {
    $items | where status != "Done" | where status != "Cancelled"
  }

  let display = $rows | select id title kind priority status | sort-by priority
  match $f {
    "json" => { $display | to json },
    "md"   => { $display | to md },
    _      => { $display | table },
  }
}

export def "backlog show" [id: string] {
  let item = (backlog-load) | where id == $id | first
  print ""
  print $"[($item.status)] ($item.id) — ($item.title)"
  print $"Kind: ($item.kind)   Priority: ($item.priority)"
  if ($item.detail? | default "" | str length) > 0 { print ""; print $item.detail }
  let adrs  = ($item.related_adrs?  | default [])
  let modes = ($item.related_modes? | default [])
  if ($adrs  | is-not-empty) { print $"ADRs:  ($adrs  | str join ', ')" }
  if ($modes | is-not-empty) { print $"Modes: ($modes | str join ', ')" }
  if ($item.related_dim?  | is-not-empty) { print $"Dimension:    ($item.related_dim)" }
  if ($item.graduates_to? | is-not-empty) { print $"Graduates to: ($item.graduates_to)" }
  print ""
}

export def "backlog add" [
  title: string,
  --kind:     string = "Todo",
  --priority: string = "Medium",
  --detail:   string = "",
  --dim:      string = "",
  --adr:      string = "",
  --mode:     string = "",
] {
  let root  = (backlog-root)
  let file  = $"($root)/reflection/backlog.ncl"
  if not ($file | path exists) {
    print $"No backlog.ncl at ($file)"
    return
  }

  let items    = (backlog-load)
  let next_num = if ($items | is-empty) { 1 } else {
    ($items | each { |i| $i.id | str replace "bl-" "" | into int } | sort | last) + 1
  }
  let new_id = $"bl-($next_num | fill --alignment right --width 3 --character '0')"
  let today  = (date now | format date "%Y-%m-%d")

  let adrs_list  = if ($adr  | str length) > 0 { [$adr]  } else { [] }
  let modes_list = if ($mode | str length) > 0 { [$mode] } else { [] }

  print ""
  print $"New backlog item: ($new_id)"
  print $"  title    = ($title)"
  print $"  kind     = ($kind)"
  print $"  priority = ($priority)"
  print ""
  print $"Add to reflection/backlog.ncl:"
  print $"  \{"
  print $"    id       = \"($new_id)\","
  print $"    title    = \"($title)\","
  print $"    kind     = '($kind),"
  print $"    priority = '($priority),"
  print $"    status   = 'Open,"
  print $"    detail   = \"($detail)\","
  print $"    created  = \"($today)\","
  print $"    updated  = \"($today)\","
  print $"  \},"
}

export def "backlog done" [id: string] {
  backlog-set-status $id "Done"
}

export def "backlog cancel" [id: string] {
  backlog-set-status $id "Cancelled"
}

export def "backlog promote" [id: string] {
  let item = (backlog-load) | where id == $id | first

  print ""
  print $"Promoting ($item.id): ($item.title)"
  print $"Graduates to: ($item.graduates_to? | default 'unset')"
  print ""

  let target = ($item.graduates_to? | default "")
  if $target == "Adr" {
    let flag = if ($item.priority == "Critical" or $item.priority == "High") { "-a " } else { "" }
    print "Run in a Claude session:"
    print $"  /create-adr ($flag)\"($item.title)\""
  } else if $target == "Mode" {
    let mode_id = ($item.title | str downcase | str replace --all " " "-" | str replace --all --regex '[^a-z0-9-]' "")
    print $"  ontoref register → affects_capability=true, mode_id=($mode_id)"
  } else if $target == "StateTransition" {
    let dim = ($item.related_dim? | default "")
    print "  ontoref register → changes_ontology_state=true"
    if ($dim | str length) > 0 { print $"  dimension_id: ($dim)" }
  } else if $target == "PrItem" {
    print "  ontoref mode create-pr"
  } else {
    print "  No graduation target set. Edit backlog.ncl to add graduates_to."
  }
  print ""
}

export def "backlog roadmap" [] {
  let root    = (backlog-root)
  let bl      = (backlog-load) | where status != "Done" | where status != "Cancelled"

  let state_file = $"($root)/.ontology/state.ncl"
  let dims = if ($state_file | path exists) {
    let data = (daemon-export-safe $state_file)
    if $data != null { $data | get dimensions } else { [] }
  } else { [] }

  print ""
  print "═══ ROADMAP ═══════════════════════════════════════"

  if ($dims | is-not-empty) {
    print ""
    print "STATE DIMENSIONS"
    for d in $dims {
      if $d.current_state != $d.desired_state {
        print $"  ($d.id)  ($d.current_state) → ($d.desired_state)  [($d.horizon)]"
      }
    }
  }

  for p in ["Critical", "High", "Medium", "Low"] {
    let p_items = $bl | where priority == $p
    if ($p_items | is-not-empty) {
      print ""
      print ($p | str upcase)
      for i in $p_items {
        let tag = if $i.status == "InProgress" { "[~]" } else { "[ ]" }
        print $"  ($tag) ($i.id)  ($i.title)  [($i.kind)]"
      }
    }
  }

  print ""
  print "═══════════════════════════════════════════════════"
  print ""
}

# ── Internal ────────────────────────────────────────────────────────────────────

def backlog-root []: nothing -> string {
  $env.ONTOREF_PROJECT_ROOT? | default $env.ONTOREF_ROOT
}

def backlog-load [] {
  let file = $"($env.ONTOREF_PROJECT_ROOT? | default $env.ONTOREF_ROOT)/reflection/backlog.ncl"
  if not ($file | path exists) { return [] }
  let data = (daemon-export-safe $file)
  if $data == null { return [] }
  $data | get items
}

def backlog-set-status [id: string, new_status: string] {
  let file  = $"($env.ONTOREF_PROJECT_ROOT? | default $env.ONTOREF_ROOT)/reflection/backlog.ncl"
  let today = (date now | format date "%Y-%m-%d")

  let lines = (open --raw $file | lines)

  # Find the line index of the id field for this item
  let id_pattern = $"\"($id)\""
  let id_line = ($lines | enumerate | where { |r| $r.item | str contains $id_pattern } | first)
  if ($id_line | is-empty) {
    print $"  error: id '($id)' not found in ($file)"
    return
  }
  let start = $id_line.index

  # Scan forward from the id line to find the closing `},` of this item record.
  # Track brace depth: the id line is already inside the outer record (depth=1 going in).
  mut depth = 0
  mut end_line = $start
  for i in ($start..($lines | length | $in - 1)) {
    let l = ($lines | get $i)
    let opens  = ($l | split chars | where $it == "{" | length)
    let closes = ($l | split chars | where $it == "}" | length)
    $depth = $depth + $opens - $closes
    if $depth < 0 {
      $end_line = $i
      break
    }
  }

  # Bind end_line to immutable before closure (Nu forbids capturing mut vars in closures)
  let end_idx = $end_line

  # Patch status and updated within the located range [start, end_idx]
  let patched = ($lines | enumerate | each { |r|
    if $r.index >= $start and $r.index <= $end_idx {
      $r.item
      | str replace --regex "status[[:space:]]*=[[:space:]]*'[A-Za-z]+" $"status   = '($new_status)"
      | str replace --regex "updated[[:space:]]*=[[:space:]]*\"[^\"]*\"" $"updated  = \"($today)\""
    } else {
      $r.item
    }
  } | str join "\n")

  $patched | save --force $file

  let tc = do { ^nickel typecheck $file } | complete
  if $tc.exit_code != 0 {
    print "  error: typecheck failed — reverting"
    do { ^git checkout -- $file } | complete | ignore
    return
  }
  print $"  ($id) → ($new_status)"
}
