- name: Install and configure Gokapi
  block:
    - name: Install unzip (required to extract Gokapi release archive)
      ansible.builtin.apt:
        name: unzip
        state: present
        update_cache: true

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

    - name: Create Gokapi system user
      ansible.builtin.user:
        name: "{{ gokapi_sys_user }}"
        group: "{{ gokapi_sys_group }}"
        shell: /usr/sbin/nologin
        home: "{{ gokapi_data_dir }}"
        create_home: false
        system: true
        state: present

    - name: Create Gokapi installation directory
      ansible.builtin.file:
        path: "{{ gokapi_install_path }}"
        state: directory
        owner: root
        group: root
        mode: "0755"

    - name: Create Gokapi data directory
      ansible.builtin.file:
        path: "{{ gokapi_data_dir }}"
        state: directory
        owner: "{{ gokapi_sys_user }}"
        group: "{{ gokapi_sys_group }}"
        mode: "0750"

    - name: Create Gokapi config directory
      ansible.builtin.file:
        path: "{{ gokapi_config_dir }}"
        state: directory
        owner: "{{ gokapi_sys_user }}"
        group: "{{ gokapi_sys_group }}"
        mode: "0750"

    - name: Create Gokapi data subdirectory for uploaded files
      ansible.builtin.file:
        path: "{{ gokapi_data_dir }}/data"
        state: directory
        owner: "{{ gokapi_sys_user }}"
        group: "{{ gokapi_sys_group }}"
        mode: "0750"

    - name: Check if Gokapi version file exists
      ansible.builtin.stat:
        path: "{{ gokapi_install_path }}/version"
      register: gokapi_version_file

    - name: Read installed Gokapi version
      when: gokapi_version_file.stat.exists
      ansible.builtin.slurp:
        src: "{{ gokapi_install_path }}/version"
      register: gokapi_installed_version_raw

    - name: Set installed Gokapi version fact
      ansible.builtin.set_fact:
        gokapi_installed_version: >-
          {{ gokapi_installed_version_raw.content | b64decode | trim
             if gokapi_version_file.stat.exists else '' }}

    - name: Download Gokapi release archive
      when: gokapi_installed_version != gokapi_version
      ansible.builtin.get_url:
        url: "{{ gokapi_archive_url }}"
        dest: "/tmp/gokapi-{{ gokapi_version }}.zip"
        checksum: "sha256:{{ gokapi_archive_sha256 }}"
        mode: "0644"

    - name: Extract Gokapi binary
      when: gokapi_installed_version != gokapi_version
      ansible.builtin.unarchive:
        src: "/tmp/gokapi-{{ gokapi_version }}.zip"
        dest: "{{ gokapi_install_path }}"
        remote_src: true
        owner: root
        group: root
        mode: "0755"
      notify: Restart gokapi

    - name: Remove downloaded Gokapi archive
      when: gokapi_installed_version != gokapi_version
      ansible.builtin.file:
        path: "/tmp/gokapi-{{ gokapi_version }}.zip"
        state: absent

    - name: Ensure Gokapi binary is executable
      when: gokapi_installed_version != gokapi_version
      ansible.builtin.file:
        path: "{{ gokapi_install_path }}/gokapi"
        owner: root
        group: root
        mode: "0755"

    - name: Write installed Gokapi version file
      when: gokapi_installed_version != gokapi_version
      ansible.builtin.copy:
        content: "{{ gokapi_version }}"
        dest: "{{ gokapi_install_path }}/version"
        owner: root
        group: root
        mode: "0644"

    - name: Stat existing Gokapi config before templating (detects prior wizard-based bootstrap)
      ansible.builtin.stat:
        path: "{{ gokapi_config_dir }}/config.json"
      register: gokapi_preexisting_config

    - name: Stat Gokapi bootstrap marker
      ansible.builtin.stat:
        path: "{{ gokapi_bootstrap_marker }}"
      register: gokapi_bootstrap_check

    - name: Template Gokapi config.json (first deploy only; preserves operator edits via admin UI)
      ansible.builtin.template:
        src: templates/config.json.j2
        dest: "{{ gokapi_config_dir }}/config.json"
        owner: "{{ gokapi_sys_user }}"
        group: "{{ gokapi_sys_group }}"
        mode: "0640"
        force: false
      notify: Restart gokapi

    - name: Migrate existing config.json Port to bind-address form (Gokapi >=2.2.4 requires ":N", not "N")
      ansible.builtin.replace:
        path: "{{ gokapi_config_dir }}/config.json"
        regexp: '"Port":\s*"([0-9]+)"'
        replace: '"Port": ":\1"'
      notify: Restart gokapi

    # Gokapi emits a broken meta-refresh on root URL when RedirectUrl is empty
    - name: Migrate empty RedirectUrl to {{ gokapi_redirect_url }}
      ansible.builtin.replace:
        path: "{{ gokapi_config_dir }}/config.json"
        regexp: '"RedirectUrl":\s*""'
        replace: '"RedirectUrl": "{{ gokapi_redirect_url }}"'
      notify: Restart gokapi

    # Gokapi has no runtime fallback; MaxFileSizeMB=0 blocks all uploads with "upload limit exceeded"
    - name: Migrate MaxFileSizeMB=0 to {{ gokapi_max_file_size_mb }}
      ansible.builtin.replace:
        path: "{{ gokapi_config_dir }}/config.json"
        regexp: '"MaxFileSizeMB":\s*0\b'
        replace: '"MaxFileSizeMB": {{ gokapi_max_file_size_mb }}'
      notify: Restart gokapi

    # Gokapi has no runtime fallback; MaxMemory=0 disables multipart memory buffering
    - name: Migrate MaxMemory=0 to {{ gokapi_max_memory_mb }}
      ansible.builtin.replace:
        path: "{{ gokapi_config_dir }}/config.json"
        regexp: '"MaxMemory":\s*0\b'
        replace: '"MaxMemory": {{ gokapi_max_memory_mb }}'
      notify: Restart gokapi

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

    - name: Mark bootstrap complete on hosts already configured by the prior wizard flow
      when:
        - not gokapi_bootstrap_check.stat.exists
        - gokapi_preexisting_config.stat.exists
      ansible.builtin.file:
        path: "{{ gokapi_bootstrap_marker }}"
        state: touch
        owner: "{{ gokapi_sys_user }}"
        group: "{{ gokapi_sys_group }}"
        mode: "0640"

    - name: Bootstrap Gokapi superadmin via --deployment-password (one-shot, first deploy only)
      when:
        - not gokapi_bootstrap_check.stat.exists
        - not gokapi_preexisting_config.stat.exists
      ansible.builtin.command:
        argv:
          - "{{ gokapi_install_path }}/gokapi"
          - "--deployment-password"
          - "{{ gokapi_admin_password }}"
      environment:
        GOKAPI_CONFIG_DIR: "{{ gokapi_config_dir }}"
        GOKAPI_DATA_DIR: "{{ gokapi_data_dir }}/data"
      become: true
      become_user: "{{ gokapi_sys_user }}"
      no_log: true
      changed_when: true

    - name: Mark Gokapi superadmin bootstrap as complete
      when:
        - not gokapi_bootstrap_check.stat.exists
        - not gokapi_preexisting_config.stat.exists
      ansible.builtin.file:
        path: "{{ gokapi_bootstrap_marker }}"
        state: touch
        owner: "{{ gokapi_sys_user }}"
        group: "{{ gokapi_sys_group }}"
        mode: "0640"

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

    - name: Deploy Gokapi Caddyfile
      ansible.builtin.template:
        src: templates/Caddyfile.j2
        dest: "/etc/caddy/sites/{{ gokapi_domain }}.caddyfile"
        owner: root
        group: root
        mode: "0644"
      notify: Restart caddy

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