---
- name: Ensure workstation user directories exist
  tags: [dotfiles, dotfiles:workstation]
  ansible.builtin.file:
    path: "{{ item.path }}"
    state: directory
    owner: "{{ username }}"
    group: "{{ user_group }}"
    mode: "{{ item.mode }}"
  loop: "{{ workstation_user_directories | default([]) }}"
  loop_control:
    label: "{{ item.path }}"

- name: Copy workstation dotfiles
  tags: [dotfiles, dotfiles:workstation]
  ansible.builtin.copy:
    src: "{{ playbook_dir }}/../dotfiles/workstation/{{ item.src }}"
    dest: "{{ user_home }}/{{ item.dest }}"
    owner: "{{ username }}"
    group: "{{ user_group }}"
    mode: "{{ item.mode }}"
  loop: "{{ workstation_dotfiles | default([]) }}"
  loop_control:
    label: "{{ item.dest }}"

- name: Render workstation templates
  tags: [dotfiles, dotfiles:workstation]
  ansible.builtin.template:
    src: "{{ item.src }}"
    dest: "{{ user_home }}/{{ item.dest }}"
    owner: "{{ username }}"
    group: "{{ user_group }}"
    mode: "{{ item.mode }}"
  loop: "{{ workstation_templates | default([]) }}"
  loop_control:
    label: "{{ item.dest }}"

- name: Set workstation external tool release metadata
  tags: [packages]
  ansible.builtin.set_fact:
    workstation_tools_tmp_dir: /tmp/workstation-tools
    opencode_asset_name: >-
      {{
        'opencode-linux-x64-baseline.tar.gz' if ansible_facts['architecture'] == 'x86_64'
        else 'opencode-linux-arm64.tar.gz' if ansible_facts['architecture'] in ['aarch64', 'arm64']
        else ''
      }}

- name: Ensure architecture is supported for OpenCode binary
  tags: [packages]
  ansible.builtin.fail:
    msg: "Unsupported architecture {{ ansible_facts['architecture'] }} for OpenCode release binary"
  when: opencode_asset_name == ''

- name: Ensure temporary directory exists for workstation external tools
  tags: [packages]
  ansible.builtin.file:
    path: "{{ workstation_tools_tmp_dir }}"
    state: directory
    mode: "0755"

- name: Fetch latest OpenCode release metadata
  tags: [packages]
  ansible.builtin.uri:
    url: https://api.github.com/repos/anomalyco/opencode/releases/latest
    headers:
      Accept: application/vnd.github+json
    return_content: true
  register: opencode_latest_release
  changed_when: false

- name: Set OpenCode release asset metadata
  tags: [packages]
  ansible.builtin.set_fact:
    opencode_version: "{{ opencode_latest_release.json.tag_name }}"
    opencode_asset: >-
      {{
        opencode_latest_release.json.assets
        | selectattr('name', 'equalto', opencode_asset_name)
        | first
        | default({})
      }}

- name: Ensure latest OpenCode asset metadata is available
  tags: [packages]
  ansible.builtin.fail:
    msg: "Could not find OpenCode asset {{ opencode_asset_name }} in release {{ opencode_version }}"
  when: opencode_asset == {}

- name: Download OpenCode release archive
  tags: [packages]
  ansible.builtin.get_url:
    url: "{{ opencode_asset.browser_download_url }}"
    dest: "{{ workstation_tools_tmp_dir }}/{{ opencode_asset.name }}"
    checksum: "{{ opencode_asset.digest | default(omit) }}"
    mode: "0644"

- name: Extract OpenCode release archive
  tags: [packages]
  ansible.builtin.unarchive:
    src: "{{ workstation_tools_tmp_dir }}/{{ opencode_asset.name }}"
    dest: "{{ workstation_tools_tmp_dir }}"
    remote_src: true

- name: Install OpenCode binary
  tags: [packages]
  ansible.builtin.copy:
    src: "{{ workstation_tools_tmp_dir }}/opencode"
    dest: /usr/local/bin/opencode
    remote_src: true
    owner: root
    group: root
    mode: "0755"

- name: Ensure GNOME extension directories exist
  tags: [packages, gnome]
  ansible.builtin.file:
    path: "{{ item }}"
    state: directory
    owner: "{{ username }}"
    group: "{{ user_group }}"
    mode: "0755"
  loop:
    - "{{ user_home }}/.cache/gnome-shell/extensions"
    - "{{ user_home }}/.local/share/gnome-shell/extensions"

- name: Gather workstation user account data
  tags: [packages, gnome]
  ansible.builtin.getent:
    database: passwd
    key: "{{ username }}"

- name: Set workstation GNOME session environment
  tags: [packages, gnome]
  ansible.builtin.set_fact:
    workstation_user_uid: "{{ ansible_facts.getent_passwd[username][1] }}"
    workstation_gnome_extension_dir: "{{ user_home }}/.cache/gnome-shell/extensions"
    workstation_gnome_environment:
      HOME: "{{ user_home }}"
      XDG_RUNTIME_DIR: "/run/user/{{ ansible_facts.getent_passwd[username][1] }}"
      DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ ansible_facts.getent_passwd[username][1] }}/bus"

- name: Download workstation GNOME extension archives
  tags: [packages, gnome]
  ansible.builtin.get_url:
    url: >-
      https://extensions.gnome.org/download-extension/{{ item.uuid }}.shell-extension.zip?version_tag={{ item.version_tag }}
    dest: "{{ workstation_gnome_extension_dir }}/{{ item.uuid }}.zip"
    owner: "{{ username }}"
    group: "{{ user_group }}"
    mode: "0644"
  loop: "{{ workstation_gnome_extensions | default([]) }}"
  loop_control:
    label: "{{ item.uuid }}"

- name: Check installed workstation GNOME extensions
  tags: [packages, gnome]
  ansible.builtin.stat:
    path: "{{ user_home }}/.local/share/gnome-shell/extensions/{{ item.uuid }}/metadata.json"
  loop: "{{ workstation_gnome_extensions | default([]) }}"
  loop_control:
    label: "{{ item.uuid }}"
  register: workstation_gnome_extension_install_state

- name: Install workstation GNOME extensions from downloaded archives
  tags: [packages, gnome]
  ansible.builtin.command:
    cmd: "gnome-extensions install --force {{ workstation_gnome_extension_dir }}/{{ item.uuid }}.zip"
  become_user: "{{ username }}"
  environment: "{{ workstation_gnome_environment }}"
  loop: "{{ workstation_gnome_extensions | default([]) }}"
  loop_control:
    label: "{{ item.uuid }}"
  when: >-
    not (
      workstation_gnome_extension_install_state.results
      | selectattr('item.uuid', 'equalto', item.uuid)
      | map(attribute='stat.exists')
      | first
      | default(false)
    )

- name: Read current workstation GNOME enabled extensions
  tags: [gnome]
  ansible.builtin.command:
    cmd: gsettings get org.gnome.shell enabled-extensions
  become_user: "{{ username }}"
  environment: "{{ workstation_gnome_environment }}"
  register: workstation_enabled_gnome_extensions_current
  changed_when: false

- name: Compute desired workstation GNOME enabled extensions
  tags: [gnome]
  ansible.builtin.set_fact:
    workstation_enabled_gnome_extensions_current_list: >-
      {{
        (
          workstation_enabled_gnome_extensions_current.stdout
          | default('')
          | regex_search('\[.*\]')
          | default('[]', true)
        )
        | from_yaml
      }}

- name: Build desired workstation GNOME enabled extensions list
  tags: [gnome]
  ansible.builtin.set_fact:
    workstation_enabled_gnome_extensions_desired: >-
      {{
        (
          workstation_enabled_gnome_extensions_current_list
          + (
            workstation_gnome_extensions
            | default([])
            | selectattr('enabled', 'defined')
            | selectattr('enabled')
            | map(attribute='uuid')
            | list
          )
        )
        | difference(workstation_disabled_gnome_extensions | default([]))
        | unique
        | sort
      }}

- name: Build workstation GNOME extensions gsettings payload
  tags: [gnome]
  ansible.builtin.set_fact:
    workstation_enabled_gnome_extensions_desired_gsettings: >-
      [{% for extension_uuid in workstation_enabled_gnome_extensions_desired -%}
      '{{ extension_uuid | replace("'", "\\'") }}'{% if not loop.last %}, {% endif %}
      {%- endfor %}]

- name: Determine whether workstation GNOME enabled extensions must change
  tags: [gnome]
  ansible.builtin.set_fact:
    workstation_gnome_extensions_state_changed: >-
      {{ (workstation_enabled_gnome_extensions_current_list | sort) != workstation_enabled_gnome_extensions_desired }}

- name: Apply workstation GNOME enabled extensions list
  tags: [gnome]
  ansible.builtin.command:
    argv:
      - gsettings
      - set
      - org.gnome.shell
      - enabled-extensions
      - "{{ workstation_enabled_gnome_extensions_desired_gsettings }}"
  become_user: "{{ username }}"
  environment: "{{ workstation_gnome_environment }}"
  changed_when: workstation_gnome_extensions_state_changed
  when: workstation_gnome_extensions_state_changed

- name: Enable UFW firewall on workstation
  tags: [services, packages]
  community.general.ufw:
    state: enabled
