# Deploy althing-chamber (https://gitea.phasefinal.com/vh/althing) to a
# Docker host following the PFI /opt/docker/ convention (ana-docker by
# default, but the playbook works against any host with Docker in place).
#
# Brings up FOUR compose services:
#   althing-chamber       — FastAPI/HTMX web UI, port 7881 host → 8000 container
#   althing-forseti       — moderator daemon, no port
#   althing-agent-runner  — Phase 2 worldtree-driver dispatcher, no port
#   althing-valkey        — Phase 3.1 valkey 8 alpine, pub/sub bridge (internal only)
#
# The three althing services use the same image (built from vh/althing);
# valkey is a stock upstream image. SQLite-backed state shares between the
# three althing services via the bind-mount under /opt/docker/conf/althing-chamber/data;
# streaming events ride pub/sub on the docker default network via valkey.
#
# Idempotent: rerunning is safe. Creates-gates skip work that's already
# done; `docker compose up -d` is itself idempotent (no restart unless
# compose content or env changed).
#
# Usage:
#   scripts/elway ana-docker --playbook playbooks/deploy-althing-chamber.yaml
#   scripts/elway ana-docker --playbook playbooks/deploy-althing-chamber.yaml --var ref=v0.1.0
#
# Prereqs on the target host:
#   - Docker + docker compose plugin
#   - Target user (lkraven) has git SSH access to gitea.phasefinal.com
#     — either SSH key authorized in gitea, or the repo is HTTPS-reachable
#     if you swap `repo_url` below.
#   - Target user is in the `docker` group.

vars:
  repo_url: git@gitea.phasefinal.com:vh/althing.git
  ref: main
  build_dir: /opt/docker/build/althing-chamber
  image_tag: althing-chamber:local
  compose_dir: /opt/docker/compose/althing-chamber
  data_dir: /opt/docker/conf/althing-chamber/data
  host_port: "7881"

steps:
  # ── host-side directory prep ─────────────────────────────────────────
  - name: Ensure /opt/docker/build parent exists
    shell: mkdir -p /opt/docker/build
    sudo: true
    creates: /opt/docker/build

  - name: Chown /opt/docker/build to lkraven (only if mkdir'd by root above)
    shell: chown lkraven:lkraven /opt/docker/build
    sudo: true
    when: '[ "$(stat -c %U /opt/docker/build)" != lkraven ]'

  # ── fetch / sync source ─────────────────────────────────────────────
  - name: Clone althing repo if absent
    # Auto-accept the first-run host key so the playbook doesn't hang
    # prompting for yes/no.
    shell: GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=accept-new" git clone {{ repo_url }} {{ build_dir }}
    creates: "{{ build_dir }}/.git"

  - name: Fetch from origin
    shell: cd {{ build_dir }} && git fetch --quiet origin

  - name: Reset working tree to {{ ref }}
    # Accept either a branch name (resolves via origin/<ref>) or a
    # full/short SHA (resolves directly). CI passes the triggering
    # commit SHA via --var ref=${{ github.sha }}; manual runs pass
    # branch names like main / v0.1.0.
    shell: |
      cd {{ build_dir }}
      if sha=$(git rev-parse --verify --quiet "origin/{{ ref }}^{commit}"); then :;
      elif sha=$(git rev-parse --verify --quiet "{{ ref }}^{commit}"); then :;
      else echo "elway: ref not found: {{ ref }}" >&2; exit 1; fi
      git reset --hard "$sha"
    # Report ok (no-change) when the tree was already at the requested
    # ref — saves a noisy CHANGED status line on no-op reruns.
    changed_when: '[ "$(cd {{ build_dir }} && git rev-parse HEAD)" != "$(cd {{ build_dir }} && (git rev-parse --verify --quiet "origin/{{ ref }}^{commit}" || git rev-parse --verify --quiet "{{ ref }}^{commit}"))" ]'

  # ── image build ─────────────────────────────────────────────────────
  - name: Build image {{ image_tag }}
    shell: cd {{ build_dir }} && docker build -t {{ image_tag }} .
    # Docker build reuses layer cache and is fast on reruns, but it
    # always runs — we can't cheaply know up-front whether anything
    # downstream has changed. Leave it in the always-run lane; Docker
    # itself handles the no-op efficiently.

  # ── compose + data dirs ─────────────────────────────────────────────
  - name: Ensure compose dir exists
    shell: mkdir -p {{ compose_dir }}
    creates: "{{ compose_dir }}"

  - name: Ensure data dir exists
    # Single bind-mount shared between chamber + forseti. Created as
    # lkraven (uid 1000 on these hosts), matching the container's `app`
    # user — no chown dance needed.
    shell: mkdir -p {{ data_dir }}
    creates: "{{ data_dir }}"

  # ── deploy compose files ────────────────────────────────────────────
  - name: Upload compose.yaml
    upload:
      src: stacks/althing-chamber/compose.yaml
      dest: "{{ compose_dir }}/compose.yaml"
      mode: "0644"

  - name: Seed .env from template (only if absent)
    upload:
      src: stacks/althing-chamber/.env.example
      dest: "{{ compose_dir }}/.env"
      mode: "0644"
    when: "[ ! -f {{ compose_dir }}/.env ]"

  # ── bring up + wait for ready ───────────────────────────────────────
  - name: docker compose up -d
    shell: cd {{ compose_dir }} && docker compose up -d

  - name: Wait for chamber /health to respond
    # Chamber's healthcheck is internal (inside the container's network);
    # this host-side poll confirms the published port is reachable too.
    # Short retry loop — docker compose up returns before the FastAPI
    # app finishes booting.
    shell: |
      for i in $(seq 1 30); do
        curl -sf -o /dev/null http://localhost:{{ host_port }}/health && exit 0
        sleep 2
      done
      exit 1
    changed_when: "false"

verify:
  - name: chamber /health returns 200
    shell: curl -sf -o /dev/null http://localhost:{{ host_port }}/health
    changed_when: "false"

  - name: chamber container running
    shell: docker ps --filter name=^/althing-chamber$ --format '{{.Status}}' | grep -q '^Up'
    changed_when: "false"

  - name: forseti container running
    shell: docker ps --filter name=^/althing-forseti$ --format '{{.Status}}' | grep -q '^Up'
    changed_when: "false"

  - name: agent-runner container running
    shell: docker ps --filter name=^/althing-agent-runner$ --format '{{.Status}}' | grep -q '^Up'
    changed_when: "false"

  - name: valkey container running + healthy
    shell: docker ps --filter name=^/althing-valkey$ --format '{{.Status}}' | grep -q 'healthy'
    changed_when: "false"
