---
# Docker Cleanup and Pruning Playbook
# Clean up unused containers, images, volumes, and networks
# Usage: ansible-playbook playbooks/prune_containers.yml
# Usage: ansible-playbook playbooks/prune_containers.yml -e "aggressive_cleanup=true"
# Usage: ansible-playbook playbooks/prune_containers.yml -e "dry_run=true"

- name: Docker System Cleanup and Pruning
  hosts: "{{ host_target | default('all') }}"
  gather_facts: yes
  vars:
    dry_run: "{{ dry_run | default(false) }}"
    aggressive_cleanup: "{{ aggressive_cleanup | default(false) }}"
    keep_images_days: "{{ keep_images_days | default(7) }}"
    keep_volumes: "{{ keep_volumes | default(true) }}"
    backup_before_cleanup: "{{ backup_before_cleanup | default(true) }}"
    cleanup_logs: "{{ cleanup_logs | default(true) }}"
    max_log_size: "{{ max_log_size | default('100m') }}"

  tasks:
    - name: Check if Docker is running
      systemd:
        name: docker
      register: docker_status
      failed_when: docker_status.status.ActiveState != "active"

    - name: Create cleanup report directory
      file:
        path: "/tmp/docker_cleanup/{{ ansible_date_time.date }}"
        state: directory
        mode: '0755'

    - name: Get pre-cleanup Docker system info
      shell: |
        echo "=== PRE-CLEANUP DOCKER SYSTEM INFO ==="
        echo "Date: {{ ansible_date_time.iso8601 }}"
        echo "Host: {{ inventory_hostname }}"
        echo ""

        echo "System Usage:"
        docker system df
        echo ""

        echo "Container Count:"
        echo "Running: $(docker ps -q | wc -l)"
        echo "Stopped: $(docker ps -aq --filter status=exited | wc -l)"
        echo "Total: $(docker ps -aq | wc -l)"
        echo ""

        echo "Image Count:"
        echo "Total: $(docker images -q | wc -l)"
        echo "Dangling: $(docker images -f dangling=true -q | wc -l)"
        echo ""

        echo "Volume Count:"
        echo "Total: $(docker volume ls -q | wc -l)"
        echo "Dangling: $(docker volume ls -f dangling=true -q | wc -l)"
        echo ""

        echo "Network Count:"
        echo "Total: $(docker network ls -q | wc -l)"
        echo "Custom: $(docker network ls --filter type=custom -q | wc -l)"
      register: pre_cleanup_info
      changed_when: false

    - name: Display cleanup plan
      debug:
        msg: |
          🧹 DOCKER CLEANUP PLAN
          ======================
          🖥️  Host: {{ inventory_hostname }}
          📅 Date: {{ ansible_date_time.date }}
          🔍 Dry Run: {{ dry_run }}
          💪 Aggressive: {{ aggressive_cleanup }}
          📦 Keep Images: {{ keep_images_days }} days
          💾 Keep Volumes: {{ keep_volumes }}
          📝 Cleanup Logs: {{ cleanup_logs }}

          {{ pre_cleanup_info.stdout }}

    - name: Backup container list before cleanup
      shell: |
        backup_file="/tmp/docker_cleanup/{{ ansible_date_time.date }}/{{ inventory_hostname }}_containers_backup.txt"

        echo "=== CONTAINER BACKUP - {{ ansible_date_time.iso8601 }} ===" > "$backup_file"
        echo "Host: {{ inventory_hostname }}" >> "$backup_file"
        echo "" >> "$backup_file"

        echo "=== RUNNING CONTAINERS ===" >> "$backup_file"
        docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}" >> "$backup_file"
        echo "" >> "$backup_file"

        echo "=== ALL CONTAINERS ===" >> "$backup_file"
        docker ps -a --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.CreatedAt}}" >> "$backup_file"
        echo "" >> "$backup_file"

        echo "=== IMAGES ===" >> "$backup_file"
        docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}" >> "$backup_file"
        echo "" >> "$backup_file"

        echo "=== VOLUMES ===" >> "$backup_file"
        docker volume ls >> "$backup_file"
        echo "" >> "$backup_file"

        echo "=== NETWORKS ===" >> "$backup_file"
        docker network ls >> "$backup_file"
      when: backup_before_cleanup | bool

    - name: Remove stopped containers
      shell: |
        {% if dry_run %}
        echo "DRY RUN: Would remove stopped containers:"
        docker ps -aq --filter status=exited
        {% else %}
        echo "Removing stopped containers..."
        stopped_containers=$(docker ps -aq --filter status=exited)
        if [ -n "$stopped_containers" ]; then
          docker rm $stopped_containers
          echo "✅ Removed stopped containers"
        else
          echo "ℹ️  No stopped containers to remove"
        fi
        {% endif %}
      register: remove_stopped_containers

    - name: Remove dangling images
      shell: |
        {% if dry_run %}
        echo "DRY RUN: Would remove dangling images:"
        docker images -f dangling=true -q
        {% else %}
        echo "Removing dangling images..."
        dangling_images=$(docker images -f dangling=true -q)
        if [ -n "$dangling_images" ]; then
          docker rmi $dangling_images
          echo "✅ Removed dangling images"
        else
          echo "ℹ️  No dangling images to remove"
        fi
        {% endif %}
      register: remove_dangling_images

    - name: Remove unused images (aggressive cleanup)
      shell: |
        {% if dry_run %}
        echo "DRY RUN: Would remove unused images older than {{ keep_images_days }} days:"
        docker images --filter "until={{ keep_images_days * 24 }}h" -q
        {% else %}
        echo "Removing unused images older than {{ keep_images_days }} days..."
        old_images=$(docker images --filter "until={{ keep_images_days * 24 }}h" -q)
        if [ -n "$old_images" ]; then
          # Check if images are not used by any container
          for image in $old_images; do
            if ! docker ps -a --format "{{.Image}}" | grep -q "$image"; then
              docker rmi "$image" 2>/dev/null && echo "Removed image: $image" || echo "Failed to remove image: $image"
            else
              echo "Skipping image in use: $image"
            fi
          done
          echo "✅ Removed old unused images"
        else
          echo "ℹ️  No old images to remove"
        fi
        {% endif %}
      register: remove_old_images
      when: aggressive_cleanup | bool

    - name: Remove dangling volumes
      shell: |
        {% if dry_run %}
        echo "DRY RUN: Would remove dangling volumes:"
        docker volume ls -f dangling=true -q
        {% else %}
        {% if not keep_volumes %}
        echo "Removing dangling volumes..."
        dangling_volumes=$(docker volume ls -f dangling=true -q)
        if [ -n "$dangling_volumes" ]; then
          docker volume rm $dangling_volumes
          echo "✅ Removed dangling volumes"
        else
          echo "ℹ️  No dangling volumes to remove"
        fi
        {% else %}
        echo "ℹ️  Volume cleanup skipped (keep_volumes=true)"
        {% endif %}
        {% endif %}
      register: remove_dangling_volumes

    - name: Remove unused networks
      shell: |
        {% if dry_run %}
        echo "DRY RUN: Would remove unused networks:"
        docker network ls --filter type=custom -q
        {% else %}
        echo "Removing unused networks..."
        docker network prune -f
        echo "✅ Removed unused networks"
        {% endif %}
      register: remove_unused_networks

    - name: Clean up container logs
      shell: |
        {% if dry_run %}
        echo "DRY RUN: Would clean up container logs larger than {{ max_log_size }}"
        find /var/lib/docker/containers -name "*-json.log" -size +{{ max_log_size }} 2>/dev/null | wc -l
        {% else %}
        {% if cleanup_logs %}
        echo "Cleaning up large container logs (>{{ max_log_size }})..."

        log_count=0
        total_size_before=0
        total_size_after=0

        for log_file in $(find /var/lib/docker/containers -name "*-json.log" -size +{{ max_log_size }} 2>/dev/null); do
          if [ -f "$log_file" ]; then
            size_before=$(stat -f%z "$log_file" 2>/dev/null || stat -c%s "$log_file" 2>/dev/null || echo 0)
            total_size_before=$((total_size_before + size_before))

            # Truncate log file to last 1000 lines
            tail -1000 "$log_file" > "${log_file}.tmp" && mv "${log_file}.tmp" "$log_file"

            size_after=$(stat -f%z "$log_file" 2>/dev/null || stat -c%s "$log_file" 2>/dev/null || echo 0)
            total_size_after=$((total_size_after + size_after))

            log_count=$((log_count + 1))
          fi
        done

        if [ $log_count -gt 0 ]; then
          saved_bytes=$((total_size_before - total_size_after))
          echo "✅ Cleaned $log_count log files, saved $(echo $saved_bytes | numfmt --to=iec) bytes"
        else
          echo "ℹ️  No large log files to clean"
        fi
        {% else %}
        echo "ℹ️  Log cleanup skipped (cleanup_logs=false)"
        {% endif %}
        {% endif %}
      register: cleanup_logs_result
      when: cleanup_logs | bool

    - name: Run Docker system prune
      shell: |
        {% if dry_run %}
        echo "DRY RUN: Would run docker system prune"
        docker system df
        {% else %}
        echo "Running Docker system prune..."
        {% if aggressive_cleanup %}
        docker system prune -af --volumes
        {% else %}
        docker system prune -f
        {% endif %}
        echo "✅ Docker system prune complete"
        {% endif %}
      register: system_prune_result

    - name: Get post-cleanup Docker system info
      shell: |
        echo "=== POST-CLEANUP DOCKER SYSTEM INFO ==="
        echo "Date: {{ ansible_date_time.iso8601 }}"
        echo "Host: {{ inventory_hostname }}"
        echo ""

        echo "System Usage:"
        docker system df
        echo ""

        echo "Container Count:"
        echo "Running: $(docker ps -q | wc -l)"
        echo "Stopped: $(docker ps -aq --filter status=exited | wc -l)"
        echo "Total: $(docker ps -aq | wc -l)"
        echo ""

        echo "Image Count:"
        echo "Total: $(docker images -q | wc -l)"
        echo "Dangling: $(docker images -f dangling=true -q | wc -l)"
        echo ""

        echo "Volume Count:"
        echo "Total: $(docker volume ls -q | wc -l)"
        echo "Dangling: $(docker volume ls -f dangling=true -q | wc -l)"
        echo ""

        echo "Network Count:"
        echo "Total: $(docker network ls -q | wc -l)"
        echo "Custom: $(docker network ls --filter type=custom -q | wc -l)"
      register: post_cleanup_info
      changed_when: false

    - name: Generate cleanup report
      copy:
        content: |
          🧹 DOCKER CLEANUP REPORT - {{ inventory_hostname }}
          ===============================================

          📅 Cleanup Date: {{ ansible_date_time.iso8601 }}
          🖥️  Host: {{ inventory_hostname }}
          🔍 Dry Run: {{ dry_run }}
          💪 Aggressive Mode: {{ aggressive_cleanup }}
          📦 Image Retention: {{ keep_images_days }} days
          💾 Keep Volumes: {{ keep_volumes }}
          📝 Log Cleanup: {{ cleanup_logs }}

          📊 BEFORE CLEANUP:
          {{ pre_cleanup_info.stdout }}

          🔧 CLEANUP ACTIONS:

          🗑️  Stopped Containers:
          {{ remove_stopped_containers.stdout }}

          🖼️  Dangling Images:
          {{ remove_dangling_images.stdout }}

          {% if aggressive_cleanup %}
          📦 Old Images:
          {{ remove_old_images.stdout }}
          {% endif %}

          💾 Dangling Volumes:
          {{ remove_dangling_volumes.stdout }}

          🌐 Unused Networks:
          {{ remove_unused_networks.stdout }}

          {% if cleanup_logs %}
          📝 Container Logs:
          {{ cleanup_logs_result.stdout }}
          {% endif %}

          🧹 System Prune:
          {{ system_prune_result.stdout }}

          📊 AFTER CLEANUP:
          {{ post_cleanup_info.stdout }}

          💡 RECOMMENDATIONS:
          - Schedule regular cleanup: cron job for this playbook
          - Monitor disk usage: ansible-playbook playbooks/disk_usage_report.yml
          - Consider log rotation: ansible-playbook playbooks/log_rotation.yml
          {% if not aggressive_cleanup %}
          - For more space: run with -e "aggressive_cleanup=true"
          {% endif %}

          ✅ CLEANUP COMPLETE

        dest: "/tmp/docker_cleanup/{{ ansible_date_time.date }}/{{ inventory_hostname }}_cleanup_report.txt"

    - name: Display cleanup summary
      debug:
        msg: |

          ✅ DOCKER CLEANUP COMPLETE - {{ inventory_hostname }}
          =============================================

          🔍 Mode: {{ 'DRY RUN' if dry_run else 'LIVE CLEANUP' }}
          💪 Aggressive: {{ aggressive_cleanup }}

          📊 SUMMARY:
          {{ post_cleanup_info.stdout }}

          📄 Full report: /tmp/docker_cleanup/{{ ansible_date_time.date }}/{{ inventory_hostname }}_cleanup_report.txt

          🔍 Next Steps:
          {% if dry_run %}
          - Run without dry_run to perform actual cleanup
          {% endif %}
          - Monitor: ansible-playbook playbooks/disk_usage_report.yml
          - Schedule regular cleanup via cron

          =============================================

    - name: Restart Docker daemon if needed
      systemd:
        name: docker
        state: restarted
      when:
        - restart_docker | default(false) | bool
        - not dry_run | bool
      register: docker_restart

    - name: Verify services after cleanup
      shell: |
        echo "Verifying critical services are still running..."
        sleep 10  # Give services time to start

        critical_services=("plex" "immich-server" "vaultwarden" "grafana" "prometheus")
        failed_services=()

        for service in "${critical_services[@]}"; do
          if ! docker ps --filter "name=$service" --format "{{.Names}}" | grep -q "$service"; then
            failed_services+=("$service")
          fi
        done

        if [ ${#failed_services[@]} -eq 0 ]; then
          echo "✅ All critical services verified running"
        else
          echo "⚠️  Some services may need attention: ${failed_services[*]}"
        fi
      register: service_verification
      when:
        - not dry_run | bool
        - verify_services | default(true) | bool

    - name: Display service verification
      debug:
        msg: "{{ service_verification.stdout }}"
      when: service_verification is defined
