---
- name: Cockpit Installation and Configuration
  block:
    - name: Validate Debian distribution
      ansible.builtin.assert:
        that:
          - ansible_facts['distribution'] == 'Debian'
        fail_msg: "Cockpit role requires Debian (detected: {{ ansible_facts['distribution'] | default('unknown') }})"

    - name: Ensure Debian backports repository is present
      ansible.builtin.apt_repository:
        repo: "deb http://deb.debian.org/debian {{ ansible_distribution_release }}-backports main"
        state: present
        filename: "{{ ansible_distribution_release }}-backports"

    - name: Install cockpit from Debian backports
      ansible.builtin.apt:
        name: cockpit
        state: present
        default_release: "{{ ansible_distribution_release }}-backports"
        update_cache: true

    - name: Get Tailscale status
      ansible.builtin.command: tailscale status --json
      register: cockpit_tailscale_status_raw
      changed_when: false
      failed_when: false

    - name: Parse Tailscale status
      ansible.builtin.set_fact:
        cockpit_tailscale_status: "{{ cockpit_tailscale_status_raw.stdout | from_json }}"
      when: cockpit_tailscale_status_raw.rc == 0
      changed_when: false

    - name: Set Tailscale IPv4 fact
      ansible.builtin.set_fact:
        cockpit_tailscale_ip: "{{ cockpit_tailscale_status.Self.TailscaleIPs | select('match', '^[0-9]+\\.') | first }}"
      when:
        - cockpit_tailscale_status_raw.rc == 0
        - cockpit_tailscale_status is defined
        - cockpit_tailscale_status.BackendState | default('') == "Running"
        - cockpit_tailscale_status.Self is defined
        - cockpit_tailscale_status.Self.TailscaleIPs is defined
        - cockpit_tailscale_status.Self.TailscaleIPs | select('match', '^[0-9]+\\.') | list | length > 0
      changed_when: false

    - name: Fail if Tailscale not available
      ansible.builtin.fail:
        msg: "Tailscale is not running or no Tailscale IP available. Cockpit requires Tailscale."
      when: cockpit_tailscale_ip is not defined

    - name: Deploy cockpit configuration
      ansible.builtin.template:
        src: cockpit.conf.j2
        dest: /etc/cockpit/cockpit.conf
        owner: root
        group: root
        mode: "0644"
      notify: Restart cockpit

    - name: Create cockpit.socket override directory
      ansible.builtin.file:
        path: /etc/systemd/system/cockpit.socket.d
        state: directory
        owner: root
        group: root
        mode: "0755"

    - name: Bind cockpit.socket to localhost only
      ansible.builtin.copy:
        content: |
          [Socket]
          ListenStream=
          ListenStream=127.0.0.1:{{ cockpit_port }}
        dest: /etc/systemd/system/cockpit.socket.d/override.conf
        owner: root
        group: root
        mode: "0644"
      notify: Restart cockpit

    - name: Enable and start cockpit.socket
      ansible.builtin.systemd:
        name: cockpit.socket
        enabled: true
        state: started
        daemon_reload: true

    - name: Check if netplan binary is present
      ansible.builtin.stat:
        path: /usr/sbin/netplan
      register: cockpit_netplan_bin
      when: cockpit_configure_nm_renderer

    - name: Ensure NetworkManager is installed
      ansible.builtin.apt:
        name: network-manager
        state: present
      when: cockpit_configure_nm_renderer and cockpit_netplan_bin.stat.exists

    - name: Ensure NetworkManager is enabled and running
      ansible.builtin.systemd_service:
        name: NetworkManager
        enabled: true
        state: started
      when: cockpit_configure_nm_renderer and cockpit_netplan_bin.stat.exists

    - name: Set NetworkManager as netplan renderer
      # The server uses netplan with the default networkd renderer, so NM has no
      # managed interfaces and reports "connected (local only)". PackageKit checks
      # NM state and treats anything below "connected (global)" as offline, breaking
      # Cockpit's software updates page. Switching the renderer lets NM manage the
      # primary network interface and properly detect internet connectivity.
      ansible.builtin.copy:
        content: |
          network:
            version: 2
            renderer: NetworkManager
        dest: /etc/netplan/99-nm-renderer.yaml
        owner: root
        group: root
        mode: "0600"
      when: cockpit_configure_nm_renderer and cockpit_netplan_bin.stat.exists
      register: cockpit_netplan_renderer

    - name: Apply netplan renderer change
      when:
        - cockpit_netplan_renderer is defined
        - cockpit_netplan_renderer.changed
        - not ansible_check_mode
      block:
        - name: Validate netplan config before applying
          ansible.builtin.command: /usr/sbin/netplan generate
          changed_when: false

        - name: Start netplan apply
          ansible.builtin.command: /usr/sbin/netplan apply
          async: 180
          poll: 0
          register: cockpit_netplan_apply_job
          changed_when: true

        - name: Give netplan apply time to interrupt networking
          ansible.builtin.pause:
            seconds: 2

        - name: Wait for SSH to return after netplan apply
          ansible.builtin.wait_for_connection:
            delay: 2
            timeout: 60

        - name: Wait for netplan apply to finish
          ansible.builtin.async_status:
            jid: "{{ cockpit_netplan_apply_job.ansible_job_id }}"
          register: cockpit_netplan_apply_status
          until: cockpit_netplan_apply_status.finished
          retries: 24
          delay: 5

    - name: Validate Cloudflare API token for Caddy DNS-01 challenge
      ansible.builtin.assert:
        that:
          - cloudflare_dns_api_token is defined
          - cloudflare_dns_api_token | length > 0
        fail_msg: "cloudflare_dns_api_token must be defined for Caddy DNS-01 TLS challenge"

    - name: Deploy Caddy site configuration
      ansible.builtin.template:
        src: cockpit.caddyfile.j2
        dest: "/etc/caddy/sites/{{ cockpit_domain }}.caddyfile"
        owner: root
        group: root
        mode: "0644"
      notify: Restart caddy

    - name: Ensure Cloudflare DNS A record exists for {{ cockpit_subdomain + '.' + domain }}
      ansible.builtin.include_role:
        name: dns_record
      vars:
        dns_record_subdomain: "{{ cockpit_subdomain }}"
        dns_record_domain: "{{ domain }}"
        dns_record_ip: "{{ cockpit_tailscale_ip }}"
        dns_record_cloudflare_api_token: "{{ cloudflare_dns_api_token }}"
