///|
/// MoonBlox init TUI wizard — interactive project scaffolding.

///|
fn theme_names() -> Array[String] {
  ["blog", "docs"]
}

///|
fn all_component_names() -> Array[String] {
  [
    "badge", "counter", "callout", "card", "grid", "metric", "chart", "graph", "sidebar",
    "breadcrumbs", "prev_next",
  ]
}

///|
fn component_label(name : String) -> String {
  match name {
    "badge" => "badge         Status badge"
    "counter" => "counter       Interactive counter"
    "callout" => "callout       Callout box"
    "card" => "card          Content card"
    "grid" => "grid          CSS grid layout"
    "metric" => "metric        Metric display"
    "chart" => "chart         Bar chart"
    "graph" => "graph         Value graph"
    "sidebar" => "sidebar       Docs sidebar"
    "breadcrumbs" => "breadcrumbs   Breadcrumb nav"
    "prev_next" => "prev_next     Prev/next page"
    _ => name
  }
}

///|
enum Step {
  Dir
  Theme
  Components
  Confirm
} derive(Eq, Debug)

///|
struct Model {
  step : Step
  dir_input : @widgets.TextInput
  theme_list : @widgets.List
  comp_cursor : Int
  comp_selected : @vector.Vector[Bool]
  width : Int
  height : Int
  status : String
} derive(Debug)

///|
enum Msg {
  KeyPressed(@tui.Key)
  Resize(@tui.Size)
} derive(Debug)

///|
fn initial_model(default_dir : String) -> Model {
  let names = all_component_names()
  let bools = Array::makei(names.length(), fn(_i) { true })
  {
    step: Dir,
    dir_input: @widgets.TextInput(placeholder="my-site", value=default_dir),
    theme_list: @widgets.List(items=theme_names()),
    comp_cursor: 0,
    comp_selected: @vector.Vector::from_array(bools),
    width: 80,
    height: 24,
    status: "Welcome to MoonBlox!",
  }
}

///|
fn accent_style() -> @tui.Style {
  @tui.Style::default().fg(@tui.Ansi(33)).bold()
}

///|
fn muted_style() -> @tui.Style {
  @tui.Style::default().fg(@tui.Ansi(244))
}

///|
fn title_style() -> @tui.Style {
  @tui.Style::default().fg(@tui.Ansi(36)).bold()
}

///|
fn step_title(step : Step) -> String {
  match step {
    Dir => "1/4  Project directory"
    Theme => "2/4  Choose theme"
    Components => "3/4  Select components"
    Confirm => "4/4  Review & confirm"
  }
}

///|
fn step_index(step : Step) -> Int {
  match step {
    Dir => 1
    Theme => 2
    Components => 3
    Confirm => 4
  }
}

///|
fn dir_value(model : Model) -> String {
  model.dir_input.value
}

///|
fn selected_theme_index(model : Model) -> Int {
  model.theme_list.selected
}

///|
fn next_step(step : Step) -> Step {
  match step {
    Dir => Theme
    Theme => Components
    Components => Confirm
    _ => step
  }
}

///|
fn prev_step(step : Step) -> Step {
  match step {
    Dir => Dir
    Theme => Dir
    Components => Theme
    Confirm => Components
  }
}

///|
fn update(
  _emit : @tui.Emit[Msg],
  msg : Msg,
  model : Model,
  result : Ref[String?],
) -> (@tui.Cmd, Model) {
  match msg {
    KeyPressed(@tui.Key::Ctrl("c")) => (@tui.Cmd::quit(), model)
    KeyPressed(@tui.Key::Escape) =>
      (@tui.Cmd::none(), { ..model, step: prev_step(model.step) })
    KeyPressed(@tui.Key::Enter) =>
      match model.step {
        Confirm => {
          let name = dir_value(model)
          let theme_name = theme_names()[selected_theme_index(model)]
          let selected_comps : Array[String] = []
          let names = all_component_names()
          for i = 0; i < names.length(); i = i + 1 {
            if i < model.comp_selected.length() && model.comp_selected[i] {
              selected_comps.push(names[i])
            }
          }
          let _ = scaffold(
            name,
            theme=theme_name,
            components=selected_comps,
            quiet=true,
          )
          result.val = Some(name)
          (@tui.Cmd::quit(), model)
        }
        Dir => {
          let name = dir_value(model)
          if name == "" {
            (
              @tui.Cmd::none(),
              { ..model, status: "Please enter a project name" },
            )
          } else {
            (@tui.Cmd::none(), { ..model, step: next_step(model.step) })
          }
        }
        Theme => (@tui.Cmd::none(), { ..model, step: next_step(model.step) })
        Components =>
          (@tui.Cmd::none(), { ..model, step: next_step(model.step) })
      }
    KeyPressed(@tui.Key::Up) =>
      (
        @tui.Cmd::none(),
        match model.step {
          Theme => {
            let msg = @widgets.ListMove(-1, 3)
            { ..model, theme_list: model.theme_list.update(msg) }
          }
          Components => {
            let count = all_component_names().length()
            {
              ..model,
              comp_cursor: if model.comp_cursor > 0 {
                model.comp_cursor - 1
              } else {
                count - 1
              },
            }
          }
          _ => model
        },
      )
    KeyPressed(@tui.Key::Down) =>
      (
        @tui.Cmd::none(),
        match model.step {
          Theme => {
            let msg = @widgets.ListMove(1, 3)
            { ..model, theme_list: model.theme_list.update(msg) }
          }
          Components => {
            let count = all_component_names().length()
            {
              ..model,
              comp_cursor: if model.comp_cursor + 1 < count {
                model.comp_cursor + 1
              } else {
                0
              },
            }
          }
          _ => model
        },
      )
    KeyPressed(@tui.Key::Char(" ")) if model.step == Components =>
      (
        @tui.Cmd::none(),
        {
          ..model,
          comp_selected: model.comp_selected.set(
            model.comp_cursor,
            !model.comp_selected[model.comp_cursor],
          ),
        },
      )
    KeyPressed(key) =>
      (
        @tui.Cmd::none(),
        match model.step {
          Dir => {
            let msg = @widgets.TextInputKey(key)
            { ..model, dir_input: model.dir_input.update(msg) }
          }
          _ => model
        },
      )
    Resize(size) =>
      (@tui.Cmd::none(), { ..model, width: size.width, height: size.height })
  }
}

///|
fn view(model : Model) -> @tui.Node {
  let width = model.width

  let step_label = step_title(model.step)
  let progress = step_index(model.step).to_string() + "/4"

  @tui.vstack([
    @tui.hstack([
      @tui.text(style=title_style(), @tui.fit_line("MoonBlox Init", width / 2)),
      @tui.text(style=muted_style(), @tui.fit_line(progress, width / 2)),
    ]),
    @tui.text(style=accent_style(), @tui.fit_line(step_label, width)),
    @tui.text(style=muted_style(), "  "),
    match model.step {
      Dir => dir_view(model, width)
      Theme => theme_view(model, width)
      Components => components_view(model, width)
      Confirm => confirm_view(model, width)
    },
    @tui.text("  "),
    @tui.text(style=muted_style(), @tui.fit_line(model.status, width)),
    @tui.text(
      style=muted_style(),
      @tui.fit_line(
        "Enter confirm  Esc back  Ctrl+C quit  Up/Down move  Space toggle", width,
      ),
    ),
  ])
}

///|
fn dir_view(model : Model, _width : Int) -> @tui.Node {
  @tui.vstack([
    @tui.text("Enter the project directory name:"),
    @tui.text("  "),
    model.dir_input.view(width=40, style=@tui.Style::default().border()),
    @tui.text("  "),
    @tui.text(
      style=muted_style(),
      "This will create a new directory with your MoonBlox site.",
    ),
  ])
}

///|
fn theme_view(model : Model, width : Int) -> @tui.Node {
  @tui.vstack([
    @tui.text("Choose a theme for your site:"),
    @tui.text("  "),
    model.theme_list.view(
      size={ width, height: 3 },
      style=@tui.Style::default(),
    ),
    @tui.text("  "),
    @tui.text(
      style=muted_style(),
      "blog \u{2014} Posts with dates, tags, article listing",
    ),
    @tui.text(
      style=muted_style(),
      "docs \u{2014} Hierarchical docs with sidebar navigation",
    ),
  ])
}

///|
fn components_view(model : Model, width : Int) -> @tui.Node {
  let names = all_component_names()
  let rows : Array[@tui.Node] = [
    @tui.text("Select components to include:"),
    @tui.text("  "),
  ]
  for i = 0; i < names.length(); i = i + 1 {
    let checked = if i < model.comp_selected.length() && model.comp_selected[i] {
      "[x]"
    } else {
      "[ ]"
    }
    let cursor = if model.comp_cursor == i { ">" } else { " " }
    let label = component_label(names[i])
    rows.push(
      @tui.text(
        style=if model.comp_cursor == i {
          accent_style()
        } else {
          @tui.Style::default()
        },
        @tui.fit_line("\{cursor} \{checked} \{label}", width),
      ),
    )
  }
  @tui.vstack(rows)
}

///|
fn confirm_view(model : Model, _width : Int) -> @tui.Node {
  let dir = dir_value(model)
  let theme_name = theme_names()[selected_theme_index(model)]
  let mut comp_list = ""
  let names = all_component_names()
  let mut count = 0
  for i = 0; i < names.length(); i = i + 1 {
    if i < model.comp_selected.length() && model.comp_selected[i] {
      if count > 0 {
        comp_list = comp_list + ", "
      }
      comp_list = comp_list + names[i]
      count = count + 1
    }
  }

  @tui.vstack([
    @tui.text(style=accent_style(), "Review your choices:"),
    @tui.text("  "),
    @tui.text("  Directory:    \{dir}"),
    @tui.text("  Theme:        \{theme_name}"),
    @tui.text("  Components:   \{comp_list}"),
    @tui.text("  "),
    @tui.text(style=accent_style(), "Press Enter to create the project."),
  ])
}

///|
fn subscriptions(_model : Model) -> @tui.Sub[Msg] {
  @tui.Sub::batch([
    @tui.Sub::keys(fn(key : @tui.Key) -> Msg { KeyPressed(key) }),
    @tui.Sub::resize(fn(size : @tui.Size) -> Msg { Resize(size) }),
  ])
}

///|
pub async fn init_tui(default_dir? : String = "") -> String? {
  let result : Ref[String?] = Ref(None)
  let app = @tui.cell(
    model=initial_model(default_dir),
    update=fn(_emit, msg, model) { update(_emit, msg, model, result) },
    view~,
    subscriptions~,
  )
  try {
    app.run_with_options(
      @tui.ProgramOptions::inline().hide_cursor(true).bracketed_paste(true),
    )
    result.val
  } catch {
    @tui.NotATty(_) => {
      println("No terminal detected. Use: moonblox-cli init ")
      None
    }
    _ => {
      println("Terminal error. Use: moonblox-cli init ")
      None
    }
  }
}