---
- name: Check if Docker is installed
  ansible.builtin.command:
    cmd: docker --version
  ignore_errors: false
  changed_when: false
  tags: dokploy, docker, installation

- name: Ensure Docker service is started and enabled
  ansible.builtin.systemd:
    name: docker
    state: started
    enabled: true
  tags: dokploy, docker, installation

- name: Leave existing Docker Swarm if any
  become: true
  community.docker.docker_swarm:
    state: absent
  ignore_errors: true
  tags: dokploy, swarm, installation

- name: Determine advertise address
  block:
    - name: Get private IP address
      ansible.builtin.set_fact:
        private_ip: "{{ ansible_default_ipv4.address }}"
      when: dokploy_advertise_addr == ""

    - name: Set advertise address
      ansible.builtin.set_fact:
        effective_advertise_addr: "{{ dokploy_advertise_addr | default(private_ip) }}"
  tags: dokploy, network, installation

- name: Validate advertise address
  ansible.builtin.assert:
    that:
      - effective_advertise_addr is defined
      - effective_advertise_addr != ""
    msg: "Could not determine advertise address. Please set dokploy_advertise_addr variable."
  tags: dokploy, network, installation

- name: Initialize Docker Swarm
  become: true
  community.docker.docker_swarm:
    state: present
    advertise_addr: "{{ effective_advertise_addr }}"
    listen_addr: "{{ effective_advertise_addr }}"
  tags: dokploy, swarm, installation

- name: Create dokploy overlay network
  become: true
  community.docker.docker_network:
    name: "{{ dokploy_docker_network }}"
    driver: overlay
    attachable: true
    state: present
  tags: dokploy, network, installation

- name: Create Dokploy configuration directory
  ansible.builtin.file:
    path: "{{ dokploy_config_dir }}"
    state: directory
    mode: "0777"
  tags: dokploy, files, installation

- name: Pull all service images (when update all services requested)
  become: true
  community.docker.docker_image:
    name: "{{ item }}"
    source: pull
  loop:
    - "{{ dokploy_postgres_image }}"
    - "{{ dokploy_redis_image }}"
    - "{{ dokploy_dokploy_image }}"
    - "{{ dokploy_traefik_image }}"
  when: dokploy_update_all_services | bool
  tags: dokploy, images, installation

- name: Pull only Dokploy image (when latest requested and not updating all)
  become: true
  community.docker.docker_image:
    name: "{{ dokploy_dokploy_image }}"
    source: pull
  when:
    - not (dokploy_update_all_services | bool)
    - dokploy_state == 'latest'
  tags: dokploy, images, installation

- name: Deploy PostgreSQL service
  become: true
  community.docker.docker_swarm_service:
    name: dokploy-postgres
    image: "{{ dokploy_postgres_image }}"
    placement:
      constraints:
        - "node.role=={{ dokploy_constraint_node_role }}"
    networks:
      - name: "{{ dokploy_docker_network }}"
        aliases:
          - dokploy-postgres
    force_update: "{{ (dokploy_state == 'latest') | bool }}"
    update_config:
      parallelism: 1
      order: stop-first
      failure_action: rollback
    restart_config:
      condition: any
      delay: 5s
      max_attempts: 3
      window: 120s
    env:
      POSTGRES_USER: "{{ dokploy_postgres_user }}"
      POSTGRES_DB: "{{ dokploy_postgres_db }}"
      POSTGRES_PASSWORD: "{{ dokploy_postgres_password }}"
    mounts:
      - type: volume
        source: dokploy-postgres-database
        target: /var/lib/postgresql/data
    state: present
  tags: dokploy, database, installation

- name: Deploy Redis service
  become: true
  community.docker.docker_swarm_service:
    name: dokploy-redis
    image: "{{ dokploy_redis_image }}"
    placement:
      constraints:
        - "node.role=={{ dokploy_constraint_node_role }}"
    networks:
      - name: "{{ dokploy_docker_network }}"
        aliases:
          - dokploy-redis
    force_update: "{{ (dokploy_state == 'latest') | bool }}"
    update_config:
      parallelism: 1
      order: stop-first
      failure_action: rollback
    restart_config:
      condition: any
      delay: 5s
      max_attempts: 3
      window: 120s
    mounts:
      - type: volume
        source: redis-data-volume
        target: /data
    state: present
  tags: dokploy, redis, installation

- name: Deploy Dokploy main service
  become: true
  community.docker.docker_swarm_service:
    name: dokploy
    image: "{{ dokploy_dokploy_image }}"
    replicas: 1
    networks:
      - name: "{{ dokploy_docker_network }}"
        aliases:
          - dokploy
    force_update: "{{ (dokploy_state == 'latest') | bool }}"
    update_config:
      parallelism: 1
      order: stop-first
      failure_action: rollback
    restart_config:
      condition: any
      delay: 5s
      max_attempts: 3
      window: 120s
    mounts:
      - type: bind
        source: /var/run/docker.sock
        target: /var/run/docker.sock
      - type: bind
        source: "{{ dokploy_config_dir }}"
        target: /etc/dokploy
      - type: volume
        source: dokploy-docker-config
        target: /root/.docker
    publish:
      - published_port: "{{ dokploy_http_port }}"
        target_port: 3000
        protocol: tcp
        mode: host
    placement:
      constraints:
        - "node.role=={{ dokploy_constraint_node_role }}"
    env:
      ADVERTISE_ADDR: "{{ effective_advertise_addr }}"
      DATABASE_URL: "postgres://{{ dokploy_postgres_user }}:{{ dokploy_postgres_password }}@dokploy-postgres:5432/{{ dokploy_postgres_db }}"
    state: present
  tags: dokploy, main, installation

- name: Wait for Dokploy to start
  ansible.builtin.pause:
    seconds: 4
  tags: dokploy, wait, installation

- name: Create Traefik configuration directories
  ansible.builtin.file:
    path: "{{ item }}"
    state: directory
    mode: "0755"
  loop:
    - "{{ dokploy_config_dir }}/traefik"
    - "{{ dokploy_config_dir }}/traefik/dynamic"
  tags: dokploy, traefik, installation

- name: Deploy Traefik service
  become: true
  community.docker.docker_swarm_service:
    name: dokploy-traefik
    image: "{{ dokploy_traefik_image }}"
    placement:
      constraints:
        - "node.role=={{ dokploy_constraint_node_role }}"
    networks:
      - name: "{{ dokploy_docker_network }}"
        aliases:
          - traefik
    update_config:
      parallelism: 1
      order: start-first
    restart_config:
      condition: any
    mounts:
      - type: bind
        source: "{{ dokploy_config_dir }}/traefik/traefik.yml"
        target: /etc/traefik/traefik.yml
      - type: bind
        source: "{{ dokploy_config_dir }}/traefik/dynamic"
        target: /etc/dokploy/traefik/dynamic
      - type: bind
        source: /var/run/docker.sock
        target: /var/run/docker.sock
    publish:
      - published_port: 443
        target_port: 443
        protocol: tcp
        mode: host
      - published_port: 80
        target_port: 80
        protocol: tcp
        mode: host
      - published_port: 443
        target_port: 443
        protocol: udp
        mode: host
    state: present
    force_update: "{{ (dokploy_state == 'latest') | bool }}"
  tags: dokploy, traefik, installation

- name: Wait for Dokploy HTTP to respond
  ansible.builtin.uri:
    url: "http://localhost:{{ dokploy_http_port }}"
    method: GET
    status_code: 200
    timeout: 30
  register: dokploy_health
  until: dokploy_health.status == 200
  retries: 10
  delay: 10
  tags: dokploy, health, installation

- name: Show installation message
  ansible.builtin.debug:
    msg:
      - "Dokploy installed successfully"
      - "Using advertise address: {{ effective_advertise_addr }}"
      - "Access at: http://{{ ansible_host }}:{{ dokploy_http_port }}"
  tags: dokploy, installation
