---
- name: Install and configure Bichon
  block:
    - name: Validate required credentials
      ansible.builtin.assert:
        that:
          - bichon_encryption_password is defined
          - bichon_encryption_password | length > 0
          - bichon_api_token is defined
          - bichon_api_token | length > 0
        fail_msg: "bichon_encryption_password and bichon_api_token must be defined"

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

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

    - name: Set Tailscale IPv4 fact
      ansible.builtin.set_fact:
        bichon_tailscale_ip: "{{ bichon_tailscale_status.Self.TailscaleIPs | select('match', '^[0-9]+\\.') | first }}"
      when:
        - bichon_tailscale_status_raw.rc == 0
        - bichon_tailscale_status is defined
        - bichon_tailscale_status.BackendState | default('') == "Running"
        - bichon_tailscale_status.Self is defined
        - bichon_tailscale_status.Self.TailscaleIPs is defined
        - bichon_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. Bichon requires Tailscale."
      when: bichon_tailscale_ip is not defined

    - name: Display Tailscale IP
      ansible.builtin.debug:
        msg: "Bichon will be accessible via Tailscale IP: {{ bichon_tailscale_ip }}"

    - name: Create system group
      ansible.builtin.group:
        name: "{{ bichon_sys_group }}"
        system: true
        state: present

    - name: Create system user
      ansible.builtin.user:
        name: "{{ bichon_sys_user }}"
        group: "{{ bichon_sys_group }}"
        shell: /usr/sbin/nologin
        home: "{{ bichon_install_dir }}"
        create_home: false
        system: true
        state: present

    - name: Create directories
      ansible.builtin.file:
        path: "{{ item }}"
        state: directory
        owner: "{{ bichon_sys_user }}"
        group: "{{ bichon_sys_group }}"
        mode: "0750"
      loop:
        - "{{ bichon_install_dir }}"
        - "{{ bichon_root_dir }}"
        - "{{ bichon_index_dir }}"
        - "{{ bichon_data_dir }}"

    - name: Check installed version
      ansible.builtin.stat:
        path: "{{ bichon_install_dir }}/version"
      register: bichon_version_file

    - name: Read installed version
      when: bichon_version_file.stat.exists
      ansible.builtin.slurp:
        src: "{{ bichon_install_dir }}/version"
      register: bichon_installed_version_raw

    - name: Set installed version fact
      ansible.builtin.set_fact:
        bichon_installed_version: >-
          {{ bichon_installed_version_raw.content | b64decode | trim
             if bichon_version_file.stat.exists else '' }}

    - name: Download and install binary
      when: bichon_installed_version != bichon_version
      block:
        - name: Download release tarball
          ansible.builtin.get_url:
            url: "{{ bichon_release_url }}"
            dest: /tmp/bichon.tar.gz
            mode: "0644"

        - name: Extract binary from tarball
          ansible.builtin.unarchive:
            src: /tmp/bichon.tar.gz
            dest: "{{ bichon_install_dir }}"
            remote_src: true
            owner: root
            group: root
            mode: "0755"

        - name: Remove tarball
          ansible.builtin.file:
            path: /tmp/bichon.tar.gz
            state: absent

    - name: Check existing encryption password file
      ansible.builtin.stat:
        path: "{{ bichon_encrypt_password_file }}"
      register: bichon_password_file

    - name: Read existing encryption password
      when: bichon_password_file.stat.exists
      ansible.builtin.slurp:
        src: "{{ bichon_encrypt_password_file }}"
      register: bichon_existing_password
      no_log: true

    - name: Fail if encryption password changed
      when:
        - bichon_password_file.stat.exists
        - (bichon_existing_password.content | b64decode | trim) != (bichon_encryption_password | trim)
      ansible.builtin.fail:
        msg: >-
          bichon_encryption_password differs from the deployed password file.
          The encryption password is permanent — changing it requires wiping all existing
          Bichon data that was encrypted with the old password. To safely rotate the password,
          first stop Bichon, back up and then delete all existing Bichon data, remove
          {{ bichon_encrypt_password_file }}, and only then re-run this playbook with the new password.

    - name: Deploy encryption password file
      when: not bichon_password_file.stat.exists
      ansible.builtin.copy:
        content: "{{ bichon_encryption_password }}"
        dest: "{{ bichon_encrypt_password_file }}"
        owner: "{{ bichon_sys_user }}"
        group: "{{ bichon_sys_group }}"
        mode: "0400"
      no_log: true
      notify: Restart bichon

    - name: Enforce encryption password file permissions
      when: bichon_password_file.stat.exists
      ansible.builtin.file:
        path: "{{ bichon_encrypt_password_file }}"
        owner: "{{ bichon_sys_user }}"
        group: "{{ bichon_sys_group }}"
        mode: "0400"

    - name: Deploy environment file
      ansible.builtin.template:
        src: bichon.env.j2
        dest: "{{ bichon_install_dir }}/bichon.env"
        owner: "{{ bichon_sys_user }}"
        group: "{{ bichon_sys_group }}"
        mode: "0600"
      no_log: true
      notify: Restart bichon

    - 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: bichon.caddyfile.j2
        dest: "/etc/caddy/sites/{{ bichon_domain }}.caddyfile"
        owner: root
        group: root
        mode: "0644"
      notify: Restart caddy

    - name: Deploy systemd service
      ansible.builtin.template:
        src: bichon.service.j2
        dest: /etc/systemd/system/bichon.service
        owner: root
        group: root
        mode: "0644"
      notify: Restart bichon

    - name: Enable and start service
      ansible.builtin.systemd_service:
        name: bichon
        enabled: true
        state: started
        daemon_reload: true

    - name: Write installed version
      when: bichon_installed_version != bichon_version
      ansible.builtin.copy:
        content: "{{ bichon_version }}"
        dest: "{{ bichon_install_dir }}/version"
        owner: "{{ bichon_sys_user }}"
        group: "{{ bichon_sys_group }}"
        mode: "0644"

    - name: Install archive script dependencies
      ansible.builtin.apt:
        name: [jq, curl]
        state: present
        update_cache: false

    - name: Create archive directories
      ansible.builtin.file:
        path: "{{ item }}"
        state: directory
        owner: "{{ bichon_sys_user }}"
        group: "{{ bichon_sys_group }}"
        mode: "0750"
      loop:
        - "{{ bichon_archive_dir }}"
        - "{{ bichon_archive_state_dir }}"

    - name: Deploy archive script
      ansible.builtin.template:
        src: bichon-archive.sh.j2
        dest: "{{ bichon_archive_script_path }}"
        owner: root
        group: root
        mode: "0755"
      notify: Restart bichon-archive timer

    - name: Deploy archive environment file
      ansible.builtin.template:
        src: bichon-archive.env.j2
        dest: "{{ bichon_archive_env_path }}"
        owner: "{{ bichon_sys_user }}"
        group: "{{ bichon_sys_group }}"
        mode: "0600"
      no_log: true
      notify: Restart bichon-archive timer

    - name: Deploy archive systemd service unit
      ansible.builtin.template:
        src: bichon-archive.service.j2
        dest: /etc/systemd/system/bichon-archive.service
        owner: root
        group: root
        mode: "0644"
      notify: Restart bichon-archive timer

    - name: Deploy archive systemd timer unit
      ansible.builtin.template:
        src: bichon-archive.timer.j2
        dest: /etc/systemd/system/bichon-archive.timer
        owner: root
        group: root
        mode: "0644"
      notify: Restart bichon-archive timer

    - name: Enable and start archive timer
      ansible.builtin.systemd_service:
        name: bichon-archive.timer
        enabled: true
        state: started
        daemon_reload: true

    - name: Display deployment summary
      ansible.builtin.debug:
        msg:
          - "==================================="
          - "Bichon Deployment Complete!"
          - "==================================="
          - "Version: {{ bichon_version }}"
          - "Data: {{ bichon_root_dir }}"
          - "Archive: {{ bichon_archive_dir }}"
          - ""
          - "Access: https://{{ bichon_domain }}"
          - ""
          - "Services:"
          - "  systemctl status bichon"
          - "  systemctl status bichon-archive.timer"
          - "  systemctl list-timers bichon-archive.timer"
