//! A terminal user interface for visualizing and debugging CI pipelines
//! (GitLab CI, GitHub Actions).
//!
//! Point it at a `.gitlab-ci.yml` or `.github/workflows/` directory and get an
//! interactive DAG view of your pipeline, with fully resolved job configurations
//! and generated shell scripts for local execution.
//!
//! # Features
//!
//! - **Pipeline DAG visualization** -- stages as columns, jobs as boxes, dependency
//!   arrows between them (both explicit `needs:` and implicit stage ordering)
//! - **Extends/anchor resolution** -- fully resolves `extends` chains, YAML anchors,
//!   `!reference` tags, and `default:` blocks so you see the final merged config
//! - **Variable expansion** -- expands `$VAR` and `${VAR:-default}` across global
//!   and job-level variables, with CI predefined variables from real git context
//! - **Local script generation** -- builds a shell script from
//!   `before_script` + `script` + `after_script` with exported variables,
//!   ready to copy and run locally
//! - **Container launch** -- press `c` to drop into an interactive container
//!   matching the job's image, with variables set and the script available to run
//! - **Four detail tabs** -- Config (resolved YAML), Script (generated bash),
//!   Variables (all expanded key-value pairs), Debug (extends chain provenance,
//!   key-level origin tracking, variable origins)
//! - **Child pipeline tabs** -- press `Enter` on a `trigger:include:local` job
//!   to open the child pipeline in a new tab; `[`/`]` to switch tabs,
//!   `Backspace` to close
//! - **Remote includes** -- fetches `include:project`, `include:remote`, and
//!   `include:template` via the GitLab API
//! - **Mouse support** -- click to select jobs/tabs, scroll to navigate,
//!   drag to resize the detail panel
//! - **Light and dark themes** -- auto-detected from terminal background;
//!   override with `--light` or `--dark`
//! - **Live reload** -- press `F5` to re-parse the file without restarting
//!
//! # Usage
//!
//! ```bash
//! # Auto-detect CI system from current directory
//! # (looks for .gitlab-ci.yml, then .github/workflows/)
//! cui-cui
//!
//! # Or specify a path
//! cui-cui path/to/.gitlab-ci.yml
//! cui-cui path/to/.github/workflows/ci.yml
//!
//! # Specify a GitLab instance (auto-detected from git remote otherwise)
//! cui-cui --gitlab-url https://gitlab.example.com .gitlab-ci.yml
//!
//! # Forward host environment variables into containers
//! cui-cui --pass-env GITHUB_TOKEN --pass-env DOCKER_PASSWORD
//!
//! # Use CI config from a separate repo (project dir is the positional arg)
//! cui-cui --ci-config ~/Src/kernel-ci/ ~/Src/linux
//!
//! # Headless modes (no TUI, for scripting/automation)
//! cui-cui --list-jobs                    # List all jobs grouped by stage
//! cui-cui --dump-script build            # Print the shell script for a job
//! cui-cui --run build                    # Run a job non-interactively (like r/R in TUI)
//! cui-cui --container build              # Drop into an interactive container (like c/C in TUI)
//!
//! # Override or set CI variables
//! cui-cui -e BUILD_OPTS="-Dfoo=true"     # Set a variable for all jobs
//!
//! # Override container registry hostname (for self-hosted GitLab instances)
//! cui-cui --ci-registry registry.gitlab.gnome.org .gitlab-ci.yml
//!
//! # Dispatch mode: run the full pipeline locally
//! cui-cui --dispatch --no-tags .                   # Run all untagged jobs
//! cui-cui --dispatch --tags kvm,x86_64 .           # Run jobs matching these tags
//! cui-cui --dispatch --no-tags --skip container-prep .  # Skip a job (treat as passed)
//! ```
//!
//! Job names in `--dump-script`, `--run`, `--container`, and `--skip` support fuzzy matching:
//! exact, case-insensitive, then substring. Hyphens and underscores are treated as
//! equivalent (`test_suite` matches `test-suite`). `--skip` also matches stage names
//! (all jobs in the stage are skipped). Use `stage=` or `job=` prefixes to
//! restrict matching. Ambiguous matches show available options.
//!
//! # Key bindings
//!
//! | Key | Action |
//! |-----|--------|
//! | `h`/`l` or Left/Right | Navigate between stages |
//! | `j`/`k` or Down/Up | Navigate between jobs within a stage |
//! | `Tab` / `Shift+Tab` | Cycle detail tabs (Config / Script / Variables / Debug) |
//! | `Enter` | Open child pipeline (trigger jobs) or toggle focus |
//! | `Backspace` | Close current child pipeline tab |
//! | `[` / `]` | Switch between pipeline tabs |
//! | `PgUp` / `PgDn` | Scroll detail panel |
//! | `H`/`L`/`K`/`J` | Scroll the DAG view |
//! | `c` | Launch interactive container for selected job |
//! | `C` | Launch privileged container (for jobs with kvm tags) |
//! | `r` | Run selected job non-interactively (shows pass/fail result) |
//! | `R` | Run selected job non-interactively with privileged mode |
//! | `v` | Edit job variables in `$EDITOR` |
//! | `F5` | Reload the file |
//! | `q` / `Esc` | Quit |
//!
//! # Supported GitLab CI features
//!
//! - `stages` ordering
//! - `extends` (single and multi-parent, with deep merge)
//! - YAML anchors, aliases, and merge keys (`<<`)
//! - `!reference` tags
//! - `include:local`, `include:project`, `include:remote`, `include:template`,
//!   `include:component`
//! - `include:inputs` and `spec:inputs` (with `$[[ inputs.* ]]` interpolation)
//! - `include:rules` (static `when: never` skipping)
//! - `needs` (DAG dependencies, optional needs, `$[[ matrix.* ]]` in
//!   `needs:parallel:matrix`)
//! - `parallel:matrix` (job expansion)
//! - `variables` (global and per-job, with expansion)
//! - `inherit:default`, `inherit:variables`
//! - `before_script`, `script`, `after_script`
//! - `run:` steps (GitLab Functions -- local `script:`, local `func:`, OCI `func:`)
//! - `image`, `services`, `tags`
//! - `rules`, `when`, `allow_failure`
//! - `artifacts` (paths, exclude, expire_in, when, `reports:dotenv`), `cache`
//! - Hidden jobs (`.name` used as templates)
//! - `default:` block
//!
//! # Supported GitHub Actions features
//!
//! - Workflow `on:` triggers
//! - Job `needs:` (DAG dependencies)
//! - `strategy.matrix` (job expansion with `${{ matrix.* }}` expressions)
//! - `env:` variables (workflow-level and job-level, with `${{ env.* }}` expansion)
//! - `${{ github.* }}` context expressions (auto-detected from local git repo)
//! - `runs-on:` labels
//! - `container:` image
//! - Per-step metadata (`uses`, `run`, `with`, `env`, `if`)
//! - `uses:` action expansion -- fetches action repos, caches them, and expands
//!   node/composite actions into executable script lines
//! - `${{ }}` expression evaluation (comparisons, boolean operators, ternary
//!   patterns like `runner.os == 'Windows' && 'win-val' || 'linux-val'`)
//! - Step output propagation (`${{ steps.X.outputs.Y }}` resolved as bash
//!   variables via `GITHUB_OUTPUT` sourcing between steps)
//! - Step-level `if:` conditions (with static evaluation where possible)
//! - `timeout-minutes`
//! - Job-level `if:` conditions
//! - GitHub predefined variables (`GITHUB_*`, `RUNNER_*`, `CI`)
//!
//! # Configuration
//!
//! cui-cui supports layered config files in TOML format. Settings are merged in
//! order (later wins):
//!
//! 1. **User config**: `$XDG_CONFIG_HOME/cui-cui/config.toml` (defaults to
//!    `~/.config/cui-cui/config.toml`)
//! 2. **Repo config**: `.cui-cui.toml` in the target directory
//! 3. **CLI arguments** (highest priority)
//!
//! Example `.cui-cui.toml`:
//!
//! ```toml
//! # Theme: "light", "dark", or "auto" (default)
//! theme = "dark"
//!
//! # GitLab instance URL
//! gitlab-url = "https://gitlab.freedesktop.org"
//!
//! # Forward host environment variables into containers
//! pass-env = ["GITHUB_TOKEN", "DOCKER_PASSWORD"]
//!
//! # CI config from a separate repo
//! ci-config = "~/Src/kernel-ci/"
//!
//! # Jobs/stages to skip in --dispatch mode (treated as passed for dependencies)
//! dispatch-skip = ["container-prep", "stage=deploy"]
//!
//! # Container image for git operations (worktree checkout, apply) in dispatch mode
//! git-image = "docker.io/alpine/git:latest"
//!
//! # Override container registry hostname (for self-hosted GitLab instances)
//! ci-registry = "registry.gitlab.gnome.org"
//!
//! # Allow unresolved extends (missing templates skipped with warning)
//! allow-unresolved = true
//! ```
//!
//! All fields are optional. Missing files are silently ignored.
//!
//! # Remote runners
//!
//! cui-cui can dispatch jobs to remote hosts via SSH. Declare runners in
//! `.cui-cui.toml` with tags, and when a job's tags match a runner, the job is
//! executed on that host instead of in a local container.
//!
//! ```toml
//! [[runner]]
//! name = "linux-builder"         # human-readable name (required)
//! host = "build-server.local"    # SSH host (omit for local runners)
//! tags = ["kvm", "x86_64"]       # tags this runner handles
//! no-tags = true                 # also pick up untagged jobs (default: false)
//! concurrency = 4                # max parallel jobs on this runner (default: 1)
//! user = "ci"                    # SSH user (default: current user)
//! port = 2222                    # SSH port (default: 22)
//! working-dir = "/opt/ci/trees"  # remote worktree base (default: ~/.cui-cui/worktrees)
//! binary = "/usr/local/bin/cui-cui"  # path to cui-cui on remote (default: "cui-cui" in PATH)
//! ```
//!
//! ## Tag matching
//!
//! A runner matches a job when the runner's tags are a **superset** of the job's
//! tags (case-insensitive). Untagged jobs only match runners with `no-tags = true`.
//! When multiple runners match, jobs are distributed proportionally by concurrency
//! to balance load across runners.
//!
//! ## Execution modes
//!
//! **Binary mode** (no `exec-prefix`): requires cui-cui installed on the
//! remote. Code is pushed via `git push`, then `cui-cui --run <job>` is invoked
//! over SSH. The remote reuses the full container/volume strategy (identical to
//! local dispatch).
//!
//! **Exec-prefix mode** (with `[runner.custom]`): no binary needed on the
//! remote. A wrapper shell script is generated locally, shipped to the remote,
//! and executed. The custom command replaces the container runtime:
//!
//! ```toml
//! [[runner]]
//! name = "vng-tester"
//! tags = ["kvm"]
//!
//! [runner.custom]
//! command = "vng --run --"       # becomes: vng --run -- ./.cui-cui-job.sh
//! ```
//!
//! ## Lifecycle hooks
//!
//! `prepare` and `cleanup` run before and after the job. Cleanup is guaranteed
//! via shell `trap EXIT` (runs on success, failure, and signals). All job
//! variables are exported before any phase, so prepare/cleanup can reference
//! them (`$CI_JOB_IMAGE`, `$CI_JOB_NAME`, custom variables, etc.).
//!
//! ```toml
//! [[runner]]
//! name = "mac-tester"
//! host = "mac-mini.local"
//! tags = ["macos"]
//!
//! [runner.custom]
//! command = "limactl shell $CI_JOB_NAME --"
//! prepare = "limactl start $CI_JOB_NAME"
//! cleanup = "limactl stop $CI_JOB_NAME"
//! ```
//!
//! Use `@file` to reference a local script instead of inline commands. The path
//! is relative to `.cui-cui.toml` (or absolute):
//!
//! ```toml
//! [runner.custom]
//! command = "limactl shell $INSTANCE --"
//! prepare = "@runners/lima-prepare.sh"
//! cleanup = "@runners/lima-cleanup.sh"
//! ```
//!
//! ## Artifacts
//!
//! Artifacts transfer automatically between runners. The local host acts as hub:
//! after a remote job succeeds, its artifacts are downloaded to the local cache;
//! before a remote job runs, needed artifacts from previous jobs are uploaded.
//!
//! ## SSH requirements
//!
//! - SSH agent must be running (or key-based auth without passphrase)
//! - `BatchMode=yes` is used -- no interactive password prompts
//! - The remote user needs write access to `~/.cui-cui/worktrees/` (or the
//!   configured `remote-dir`)
//!
//! # Architecture
//!
//! Data flows through the crate as a pipeline:
//!
//! ```text
//! YAML files ─► parser ─► model (raw) ─► resolve ─► model (resolved) ─► graph ─► ui
//! ```
//!
//! - [`parser`] -- loads CI config files. GitLab: `include:`, `!reference`,
//!   YAML anchors. GitHub: workflow files, matrix expansion, `${{ }}` expressions.
//! - [`resolve`] -- walks `extends:` chains, expands variables, expands
//!   `parallel:matrix`, resolves `needs:` references.
//! - [`model`] -- data structures: [`model::RawPipeline`] (pre-resolution),
//!   [`model::Job`] / [`model::Pipeline`] (resolved), [`model::CiSystem`].
//! - [`graph`] -- builds a `petgraph` DAG from a resolved pipeline and computes
//!   a layered layout (stage columns, job rows, edge routing).
//! - [`ui`] -- `ratatui`-based TUI: DAG view, job detail panel, input handling.
//! - [`app`] -- TUI state: selected job, scroll positions, pipeline tabs, reload.
//!
//! Execution side:
//!
//! - [`container`] -- detects podman/docker, mounts the project (bind mount or
//!   git-worktree volume with alternates), runs the job script.
//! - [`dispatch`] -- runs multiple jobs in dependency order, passes artifacts,
//!   routes jobs to runners by tag matching.
//! - [`remote`] -- ships code to a remote host via SSH (git push or diff) and
//!   runs `cui-cui --run` / `cui-cui --container` there.
//! - [`artifacts`] -- copies artifact files between jobs in a dispatch run.
//! - [`config`] -- loads `.cui-cui.toml` (runner definitions, default flags).
//! - [`git_utils`] -- shells out to `git` for branch, SHA, remote URL, etc.

pub mod app;
pub mod artifacts;
pub mod config;
pub mod container;
pub mod dispatch;
pub mod expr;
pub mod git_utils;
pub mod graph;
pub mod model;
pub mod parser;
pub mod remote;
pub mod resolve;
pub mod ui;
