---
- name: Ensure multipass is installed and create a VM with cloud-init
  hosts: localhost
  gather_facts: yes
  vars_prompt:
    - name: vm_name
      prompt: "What is the VM name (don't use spaces)?"
      private: no
      default: testvm
  vars:
    vm_image: 24.04
    vm_disk: 15G
    vm_memory: 4G
    vm_cpus: 1
    ssh_key_name: "{{ vm_name }}_ssh_key"

  tasks:
    - name: Check if VM already exists
      command: multipass list --format json
      register: vm_list_json

    - name: Parse VM list
      set_fact:
        vm_exists: "{{ vm_name in ((vm_list_json.stdout | from_json).list | map(attribute='name') | list) }}"

    - name: Output message if VM already exists
      debug:
        msg: "VM with name '{{ vm_name }}' already exists. No action will be taken."
      when: vm_exists

    - name: Gather OS facts
      setup:
        filter: "ansible_distribution"
      when: not vm_exists

    - name: Detect OS
      set_fact:
        os_type: "{{ ansible_facts['distribution'] }}"

    - name: Check if Homebrew is installed (macOS)
      command: brew --version
      register: homebrew_check
      ignore_errors: yes
      when: os_type == "MacOSX" and not vm_exists

    - name: Install Homebrew (macOS)
      shell: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
      when: os_type == "MacOSX" and homebrew_check.failed and not vm_exists

    - name: Check if multipass is installed
      shell: "command -v multipass || echo 'not found'"
      register: multipass_check
      changed_when: false

    - name: Install multipass using Homebrew (macOS)
      homebrew:
        name: multipass
        state: present
      when: 
        - os_type == "MacOSX"
        - multipass_check.stdout == "not found"
        - not vm_exists

    - name: Install multipass using snap (Ubuntu)
      snap:
        name: multipass
        state: present
      when: 
        - os_type == "Ubuntu"
        - multipass_check.stdout == "not found"
        - not vm_exists
    
    - name: Generate SSH key pair
      command: ssh-keygen -t rsa -b 2048 -f ./{{ ssh_key_name }} -N "" -C "ubuntu"
      args:
        creates: ./{{ ssh_key_name }}
      when: not vm_exists

    - name: Read the public SSH key
      command: cat ./{{ ssh_key_name }}.pub
      register: ssh_public_key
      when: not vm_exists

    - name: Create cloud-init.yaml file
      copy:
        dest: ./cloud-init.yaml
        content: |
          ## cloud-init

          users:
            - name: ubuntu
              ssh-authorized-keys:
                - {{ ssh_public_key.stdout }}
              sudo: ['ALL=(ALL) NOPASSWD:ALL']
              groups: sudo
              shell: /bin/bash

          package_update: true
          packages:
            - python3-pip
            - python3
            - python-is-python3
            - python3-venv

          hostname: {{ vm_name }}
          fqdn: {{ vm_name }}.local

          final_message: "The instance is now up for $UPTIME seconds"
      when: not vm_exists

    - name: Verify cloud-init.yaml file exists
      stat:
        path: ./cloud-init.yaml
      register: cloud_init_file
      when: not vm_exists

    - name: Fail if cloud-init.yaml does not exist
      fail:
        msg: "cloud-init.yaml file does not exist"
      when: 
        - not vm_exists
        - cloud_init_file is defined
        - not cloud_init_file.stat.exists | default(false)
    
    - name: Launch VM with multipass
      command: multipass launch {{ vm_image }} --name {{ vm_name }} --disk {{ vm_disk }} -m {{ vm_memory }} --cloud-init ./cloud-init.yaml
      register: vm_launch
      when: not vm_exists

    - name: Get VM info
      command: multipass info {{ vm_name }} --format json
      register: vm_info_json
      when: not vm_exists

    - name: Parse VM IP address
      set_fact:
        vm_ip: "{{ (vm_info_json.stdout | from_json).info[vm_name].ipv4[0] }}"
      when: not vm_exists

    - name: Generate inventory file
      copy:
        dest: ./inventory.yml
        content: |
          all:
            hosts:
              {{ vm_name }}:
                ansible_host: {{ vm_ip }}
                ansible_python_interpreter: /usr/bin/python3
            vars:
              ansible_user: ubuntu
              ansible_ssh_private_key_file: ./{{ ssh_key_name }}
      when: not vm_exists

    - name: Add VM hostname to local /etc/hosts
      become: yes
      lineinfile:
        path: /etc/hosts
        line: "{{ vm_ip }} {{ vm_name }}.local"
        state: present
      when: not vm_exists
  
    - name: Wait for VM to be ready
      wait_for:
        host: "{{ vm_ip }}"
        port: 22
        delay: 10
        timeout: 300
      when: not vm_exists

