---
- name: Configuration
  block:
    - name: Generate fstab
      ansible.builtin.shell: genfstab -LU /mnt > /mnt/etc/fstab
      changed_when: result.rc == 0
      register: result

    - name: Remove depricated attr2 and disable large extent
      when: os in ["almalinux", "rhel8", "rhel9", "rocky"] and filesystem == "xfs"
      ansible.builtin.replace:
        path: /mnt/etc/fstab
        regexp: '(xfs.*?)(attr2)'
        replace: '\1allocsize=64m'

    - name: Replace ISO UUID entry with /dev/sr0 in fstab
      when: os in ["rhel8", "rhel9"]
      ansible.builtin.lineinfile:
        path: /mnt/etc/fstab
        regexp: '^.*\/dvd.*$'
        line: "{{ '/usr/local/install/redhat/rhel.iso /usr/local/install/redhat/dvd iso9660 loop,nofail 0 0' if hypervisor == 'vmware'
              else '/dev/sr0 /usr/local/install/redhat/dvd iso9660 ro,relatime,nojoliet,check=s,map=n,nofail 0 0' }}"
        state: present
        backrefs: true

    - name: Write image from RHEL ISO to the target machine
      when: os in ["rhel8", "rhel9"] and hypervisor == 'vmware'
      ansible.builtin.command: dd if=/dev/sr1 of=/mnt/usr/local/install/redhat/rhel.iso bs=4M
      changed_when: result.rc == 0
      register: result

    - name: Append TempFS to fstab
      ansible.builtin.lineinfile:
        path: /mnt/etc/fstab
        line: "{{ item }}"
        insertafter: EOF
      with_items:
        - ""
        - "# TempFS"
        - tmpfs           /tmp            tmpfs           defaults,nosuid,nodev,noexec    0 0
        - tmpfs           /var/tmp        tmpfs           defaults,nosuid,nodev,noexec    0 0
        - tmpfs           /dev/shm        tmpfs           defaults,noexec    0 0

    - name: Set local timezone
      ansible.builtin.command: "{{ item }}"
      changed_when: result.rc == 0
      register: result
      with_items:
        - systemctl daemon-reload
        - arch-chroot /mnt ln -sf /usr/share/zoneinfo/Europe/Vienna /etc/localtime

    - name: Setup locales
      block:
        - name: Configure locale.gen
          when: os | lower not in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rocky']
          ansible.builtin.lineinfile:
            dest: /mnt/etc/locale.gen
            regexp: "{{ item.regex }}"
            line: "{{ item.line }}"
          loop:
            - { regex: en_US\.UTF-8 UTF-8, line: en_US.UTF-8 UTF-8 }

        - name: Generate locales
          when: os | lower not in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rocky']
          ansible.builtin.command: arch-chroot /mnt /usr/sbin/locale-gen
          changed_when: result.rc == 0
          register: result

        - name: Set hostname
          ansible.builtin.copy:
            content: "{{ hostname }}"
            dest: /mnt/etc/hostname
            mode: '0644'

        - name: Add host entry to /etc/hosts
          ansible.builtin.lineinfile:
            path: /mnt/etc/hosts
            line: "{{ ansible_host }}    {{ hostname }}"
            state: present

        - name: Create vconsole.conf
          ansible.builtin.copy:
            content: KEYMAP=us
            dest: /mnt/etc/vconsole.conf
            mode: '0644'

        - name: Create locale.conf
          ansible.builtin.copy:
            content: LANG=en_US.UTF-8
            dest: /mnt/etc/locale.conf
            mode: '0644'

        - name: SSH permit Password
          ansible.builtin.replace:
            path: /mnt/etc/ssh/sshd_config
            regexp: "#PasswordAuthentication yes"
            replace: PasswordAuthentication yes

        - name: SSH permit root login
          ansible.builtin.replace:
            path: /mnt/etc/ssh/sshd_config
            regexp: "^#?PermitRootLogin.*"
            replace: "PermitRootLogin yes"

    - name: Enable Systemd Services
      ansible.builtin.command: >
        arch-chroot /mnt systemctl enable NetworkManager
        {{
          ' ssh' if os | lower in ['ubuntu', 'ubuntu-lts'] else
          (' sshd' if os | lower not in ['debian11', 'debian12'] else '')
        }}
        {{
          'logrotate systemd-resolved systemd-timesyncd systemd-networkd'
          if os | lower == 'archlinux' else ''
        }}
      changed_when: result.rc == 0
      register: result

    - name: Configure grub
      when: os | lower not in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rocky']
      block:
        - name: Add commandline information to grub config
          ansible.builtin.lineinfile:
            dest: /mnt/etc/default/grub
            regexp: ^GRUB_CMDLINE_LINUX_DEFAULT=
            line: GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3"

        - name: Change Grub time
          ansible.builtin.lineinfile:
            dest: /mnt/etc/default/grub
            regexp: ^GRUB_TIMEOUT=
            line: GRUB_TIMEOUT=1

    - name: Configure Bootloader
      block:
        - name: Install Bootloader
          ansible.builtin.command: arch-chroot /mnt
            {% if os | lower not in ["archlinux", "debian11", "debian12", "ubuntu", "ubuntu-lts"] %} /usr/sbin/efibootmgr
            -c -L '{{ os }}' -d "{{ install_drive }}" -p 1
            -l '\efi\EFI\{% if os | lower in ["rhel8", "rhel9"] %}redhat{% else %}{{ os | lower }}{% endif %}\shimx64.efi'
            {% else %}/usr/sbin/grub-install --target=x86_64-efi --efi-directory={{ "/boot/efi" if os | lower in ["ubuntu", "ubuntu-lts"] else "/boot" }}
            --bootloader-id={{ "ubuntu" if os | lower in ["ubuntu", "ubuntu-lts"] else os }}
            {% endif %}
          changed_when: result.rc == 0
          register: result

        - name: Generate grub config
          ansible.builtin.command: arch-chroot /mnt
            {% if os | lower not in ["archlinux", "debian11", "debian12", "ubuntu", "ubuntu-lts"] %}
            /usr/sbin/grub2-mkconfig -o /boot/efi/EFI/{% if os | lower in ["rhel8", "rhel9"] %}redhat{% else %}{{ os | lower }}{% endif %}/grub.cfg
            {% else %}
            /usr/sbin/grub-mkconfig -o {{ "/boot/efi/EFI/ubuntu/grub.cfg" if os | lower in ["ubuntu", "ubuntu-lts"] else "/boot/grub/grub.cfg" }}
            {% endif %}
          changed_when: result.rc == 0
          register: result

        - name: Ensure lvm2 for non btrfs filesystems
          when: os | lower == "archlinux" and filesystem != "btrfs"
          ansible.builtin.lineinfile:
            path: /mnt/etc/mkinitcpio.conf
            regexp: '^(HOOKS=.*block)(?!.*lvm2)(.*)'
            line: '\1 lvm2\2'
            backrefs: true

        - name: Regenerate initramfs
          when: os | lower not in ["debian11", "debian12", "ubuntu", "ubuntu-lts"]
          ansible.builtin.command: arch-chroot /mnt
            {% if os | lower == "archlinux" %} /usr/sbin/mkinitcpio -P
            {% elif os | lower not in ["debian11", "debian12", "ubuntu", "ubuntu-lts", "archlinux"] %} /usr/bin/dracut --regenerate-all --force
            {% else %} echo "Skipping initramfs regeneration"
            {% endif %}
          changed_when: result.rc == 0
          register: result

    - name: Extra Configuration
      block:
        - name: Append vim configurations to vimrc
          failed_when: false
          ansible.builtin.blockinfile:
            path: "{{ '/mnt/etc/vim/vimrc' if os | lower in ['debian11', 'debian12', 'ubuntu', 'ubuntu-lts']
                  else '/mnt/etc/vimrc' }}"
            block: |
              set encoding=utf-8
              set number
              set autoindent
              set smartindent
              set mouse=a
            insertafter: EOF
            marker: ""

        - name: Add memory tuning parameters
          ansible.builtin.blockinfile:
            path: /mnt/etc/sysctl.d/90-memory.conf
            create: true
            block: |
              vm.swappiness=10
              vm.vfs_cache_pressure=50
              vm.dirty_background_ratio=1
              vm.dirty_ratio=10
              vm.page-cluster=10
            marker: ""
            mode: '0644'

        - name: Create zram config
          ansible.builtin.copy:
            dest: /mnt/etc/systemd/zram-generator.conf
            content: |
              [zram0]
              zram-size  = ram / 2
              compression-algorithm = zstd
              swap-priority = 100
              fs-type = swap
            mode: '0644'

        - name: Copy FirstRun Script
          when: os | lower != "archlinux"
          ansible.builtin.template:
            src: firstrun.sh.j2
            dest: /mnt/root/firstrun.sh
            mode: "0755"

        - name: Copy Custom Shell config
          ansible.builtin.template:
            src: custom.sh.j2
            dest: /mnt/etc/profile.d/custom.sh
            mode: '0644'

    - name: Setup Network
      block:
        - name: Generate UUID for Network Profile
          ansible.builtin.command: uuidgen
          changed_when: net_uuid.rc == 0
          register: net_uuid

        - name: Retrieve Network Interface Name
          ansible.builtin.shell: set -o pipefail && ip r | awk 'NR==1 {print $5}'
          changed_when: net_inf.rc == 0
          register: net_inf

        - name: Register MAC Address of the Network Interface
          ansible.builtin.shell: set -o pipefail && ip link show "{{ net_inf.stdout }}" | awk '/link\/ether/ {print $2}' | tr '[:lower:]' '[:upper:]'
          register: net_mac
          changed_when: net_mac.rc == 0

        - name: Copy NetworkManager keyfile
          ansible.builtin.template:
            src: network.j2
            dest: /mnt/etc/NetworkManager/system-connections/LAN.nmconnection
            mode: "0600"

        - name: Fix Ubuntu unmanaged devices
          when: os | lower in ["ubuntu", "ubuntu-lts"]
          ansible.builtin.file:
            path: /mnt/etc/NetworkManager/conf.d/10-globally-managed-devices.conf
            state: touch
            mode: '0644'

    - name: Setup user account
      block:
        - name: Create user account
          ansible.builtin.command: "{{ item }}"
          with_items:
            - arch-chroot /mnt /usr/sbin/useradd --create-home --user-group --groups
              {{ "sudo" if os | lower in ["debian11", "debian12", "ubuntu", "ubuntu-lts"] else "wheel" }}
              {{ user_name }} --password {{ user_password | password_hash('sha512') }} --shell /bin/bash
            - arch-chroot /mnt /usr/sbin/usermod --password '{{ root_password | password_hash('sha512') }}' root --shell /bin/bash
          changed_when: result.rc == 0
          register: result

        - name: Add SSH public key to authorized_keys
          when: user_public_key is defined
          ansible.builtin.lineinfile:
            path: /mnt/home/{{ user_name }}/.ssh/authorized_keys
            line: "{{ user_public_key }}"
            owner: 1000
            group: 1000
            mode: "0600"
            create: true

    - name: Give sudo access to wheel group
      ansible.builtin.copy:
        content: "{{ '%sudo ALL=(ALL) ALL' if os | lower in ['debian11', 'debian12', 'ubuntu', 'ubuntu-lts'] else '%wheel ALL=(ALL) ALL' }}"
        dest: /mnt/etc/sudoers.d/01-wheel
        mode: "0440"
        validate: /usr/sbin/visudo --check --file=%s

    - name: Fix SELinux
      block:
        - name: Relabel the filesystem
          when: os | lower in ['almalinux', 'rhel8', 'rhel9', 'rocky']
          ansible.builtin.command: "arch-chroot /mnt /sbin/fixfiles onboot"
          changed_when: result.rc == 0
          register: result

        - name: Disable SELinux
          when: os | lower == "fedora"
          ansible.builtin.lineinfile:
            path: /mnt/etc/selinux/config
            regexp: ^SELINUX=
            line: SELINUX=permissive