---
# showcase/common.yml — Common setup tasks for all showcase instances
#
# Included by showcase-post-deploy.yml after name parsing.
# Uses vars from the parent play: incus_api, incus_cert, incus_key,
# base_packages, ffsdn_*, blueprint_name, component_name.
#
# Adds a temporary incusbr0 NIC for internet access during package
# installation (OVN SNAT may not provide outbound internet in all labs),
# then the deploy-instance playbook removes it after setup completes.

# ── Step 1: Add temporary internet NIC ──────────────────────────────

- name: Add temporary incusbr0 NIC for internet access
  ansible.builtin.uri:
    url: "{{ incus_api }}/1.0/instances/{{ ffsdn_instance_name }}"
    method: PATCH
    client_cert: "{{ incus_cert }}"
    client_key: "{{ incus_key }}"
    validate_certs: false
    body_format: json
    body:
      devices:
        eth-setup:
          type: nic
          network: incusbr0
          name: eth1
    status_code: [200, 202]
    return_content: true
  register: nic_add_result

- name: Wait for NIC addition if async
  ansible.builtin.uri:
    url: "{{ incus_api }}{{ nic_add_result.json.operation }}/wait?timeout=30"
    method: GET
    client_cert: "{{ incus_cert }}"
    client_key: "{{ incus_key }}"
    validate_certs: false
    return_content: true
  when: nic_add_result.status == 202

- name: Push NIC activation script
  ansible.builtin.uri:
    url: "{{ incus_api }}/1.0/instances/{{ ffsdn_instance_name }}/files?path=/tmp/activate-eth1.sh"
    method: POST
    client_cert: "{{ incus_cert }}"
    client_key: "{{ incus_key }}"
    validate_certs: false
    body: |
      #!/bin/bash
      # Configure eth1 for DHCP via systemd-networkd
      mkdir -p /etc/systemd/network
      cat > /etc/systemd/network/80-eth1.network << 'EOF'
      [Match]
      Name=eth1
      [Network]
      DHCP=yes
      [DHCPv4]
      RouteMetric=100
      EOF
      ip link set eth1 up
      systemctl restart systemd-networkd
      # Wait up to 15s for IPv4 address
      for i in $(seq 1 15); do
        if ip -4 addr show eth1 | grep -q 'inet '; then
          exit 0
        fi
        sleep 1
      done
      # Last resort: try dhclient
      dhclient eth1 2>/dev/null || true
      sleep 2
    headers:
      Content-Type: "application/octet-stream"
      X-Incus-type: "file"
      X-Incus-mode: "0755"
    status_code: [200]

- name: Activate temporary NIC inside container
  ansible.builtin.uri:
    url: "{{ incus_api }}/1.0/instances/{{ ffsdn_instance_name }}/exec"
    method: POST
    client_cert: "{{ incus_cert }}"
    client_key: "{{ incus_key }}"
    validate_certs: false
    body_format: json
    body:
      command: ["/bin/bash", "/tmp/activate-eth1.sh"]
      record-output: true
      interactive: false
      wait-for-websocket: false
    status_code: [202]
    return_content: true
  register: nic_activate_exec

- name: Wait for NIC activation (up to 30s)
  ansible.builtin.uri:
    url: "{{ incus_api }}{{ nic_activate_exec.json.operation }}/wait?timeout=30"
    method: GET
    client_cert: "{{ incus_cert }}"
    client_key: "{{ incus_key }}"
    validate_certs: false
    return_content: true

- name: Wait for DHCP on temporary NIC (up to 30s)
  ansible.builtin.uri:
    url: "{{ incus_api }}/1.0/instances/{{ ffsdn_instance_name }}/state"
    method: GET
    client_cert: "{{ incus_cert }}"
    client_key: "{{ incus_key }}"
    validate_certs: false
    return_content: true
  register: nic_state
  until: >-
    nic_state.json.metadata.network is defined and
    nic_state.json.metadata.network.eth1 is defined and
    nic_state.json.metadata.network.eth1.addresses | selectattr('family', 'equalto', 'inet') | list | length > 0
  retries: 6
  delay: 5

# ── Step 2: Run base setup with internet access ────────────────────

- name: Generate base setup script
  ansible.builtin.set_fact:
    base_setup_script: |
      #!/bin/bash
      set -e

      echo "=== Showcase base setup starting ==="
      echo "Blueprint: {{ blueprint_name }}, Component: {{ component_name }}"

      # Set hostname
      hostname {{ ffsdn_instance_name }}
      echo "{{ ffsdn_instance_name }}" > /etc/hostname
      sed -i '/^127\.0\.1\.1/d' /etc/hosts
      echo "127.0.1.1 {{ ffsdn_instance_name }}" >> /etc/hosts
      echo "[OK] Hostname set to {{ ffsdn_instance_name }}"

      # Update package cache and install base packages
      export DEBIAN_FRONTEND=noninteractive
      apt-get update -qq
      apt-get install -y -qq {{ base_packages }} 2>&1 | tail -1
      echo "[OK] Base packages installed"

      # Set timezone
      ln -sf /usr/share/zoneinfo/UTC /etc/localtime
      echo "UTC" > /etc/timezone
      echo "[OK] Timezone set to UTC"

      # Write deployment metadata
      cat > /etc/deploy-info << 'DEPLOYINFO'
      blueprint={{ blueprint_name }}
      component={{ component_name }}
      hostname={{ ffsdn_instance_name }}
      ip={{ ffsdn_instance_ip | default('unknown') }}
      cluster={{ ffsdn_cluster_name | default('unknown') }}
      deployed_by={{ ffsdn_deployed_by | default('unknown') }}
      image={{ ffsdn_image_os | default('') }}/{{ ffsdn_image_release | default('') }}
      DEPLOYINFO
      echo "deployed=$(date -Iseconds)" >> /etc/deploy-info
      echo "[OK] Deployment metadata written"

      echo "=== Showcase base setup complete ==="

- name: Push base setup script to instance
  ansible.builtin.uri:
    url: "{{ incus_api }}/1.0/instances/{{ ffsdn_instance_name }}/files?path=/tmp/showcase-setup.sh"
    method: POST
    client_cert: "{{ incus_cert }}"
    client_key: "{{ incus_key }}"
    validate_certs: false
    body: "{{ base_setup_script }}"
    headers:
      Content-Type: "application/octet-stream"
      X-Incus-type: "file"
      X-Incus-mode: "0755"
    status_code: [200]

- name: Execute base setup script
  ansible.builtin.uri:
    url: "{{ incus_api }}/1.0/instances/{{ ffsdn_instance_name }}/exec"
    method: POST
    client_cert: "{{ incus_cert }}"
    client_key: "{{ incus_key }}"
    validate_certs: false
    body_format: json
    body:
      command: ["/bin/bash", "/tmp/showcase-setup.sh"]
      record-output: true
      interactive: false
      wait-for-websocket: false
      environment:
        DEBIAN_FRONTEND: "noninteractive"
    status_code: [202]
    return_content: true
  register: base_setup_exec

- name: Wait for base setup to complete (up to 3 minutes)
  ansible.builtin.uri:
    url: "{{ incus_api }}{{ base_setup_exec.json.operation }}/wait?timeout=180"
    method: GET
    client_cert: "{{ incus_cert }}"
    client_key: "{{ incus_key }}"
    validate_certs: false
    return_content: true
    timeout: 200
  register: base_setup_wait
  failed_when: base_setup_wait.json.metadata.status != "Success"

- name: Verify base setup exit code
  ansible.builtin.assert:
    that:
      - base_setup_wait.json.metadata.metadata.return | int == 0
    fail_msg: "Base setup exited with code {{ base_setup_wait.json.metadata.metadata.return }}"
    success_msg: "Base setup completed successfully"

- name: Clean up base setup script
  ansible.builtin.uri:
    url: "{{ incus_api }}/1.0/instances/{{ ffsdn_instance_name }}/exec"
    method: POST
    client_cert: "{{ incus_cert }}"
    client_key: "{{ incus_key }}"
    validate_certs: false
    body_format: json
    body:
      command: ["/bin/rm", "-f", "/tmp/showcase-setup.sh"]
      record-output: false
      interactive: false
      wait-for-websocket: false
    status_code: [202]
  ignore_errors: true
