---
- name: Container Dependency Mapping and Orchestration
  hosts: all
  gather_facts: yes
  vars:
    dependency_timestamp: "{{ ansible_date_time.iso8601 }}"
    dependency_report_dir: "/tmp/dependency_reports"
    restart_timeout: 300
    health_check_retries: 5
    health_check_delay: 10

  tasks:
    - name: Create dependency reports directory
      file:
        path: "{{ dependency_report_dir }}"
        state: directory
        mode: '0755'
      delegate_to: localhost
      run_once: true

    - name: Check if Docker is available
      shell: command -v docker >/dev/null 2>&1
      register: docker_available
      changed_when: false
      ignore_errors: yes

    - name: Skip Docker tasks if not available
      set_fact:
        skip_docker: "{{ docker_available.rc != 0 }}"

    - name: Get all running containers
      shell: |
        docker ps --format "{{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || echo "No containers"
      register: running_containers
      changed_when: false
      when: not skip_docker

    - name: Get all containers (including stopped)
      shell: |
        docker ps -a --format "{{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || echo "No containers"
      register: all_containers
      changed_when: false
      when: not skip_docker

    - name: Analyze Docker Compose dependencies
      shell: |
        echo "=== DOCKER COMPOSE DEPENDENCY ANALYSIS ==="

        # Find all docker-compose files
        compose_files=$(find /opt /home -name "docker-compose*.yml" -o -name "compose*.yml" 2>/dev/null | head -20)

        if [ -z "$compose_files" ]; then
          echo "No Docker Compose files found"
          exit 0
        fi

        echo "Found Docker Compose files:"
        echo "$compose_files"
        echo ""

        # Analyze dependencies in each compose file
        for compose_file in $compose_files; do
          if [ -f "$compose_file" ]; then
            echo "=== Analyzing: $compose_file ==="

            # Extract service names
            services=$(grep -E "^  [a-zA-Z0-9_-]+:" "$compose_file" | sed 's/://g' | sed 's/^  //' | sort)
            echo "Services: $(echo $services | tr '\n' ' ')"

            # Look for depends_on relationships
            echo "Dependencies found:"
            grep -A 5 -B 1 "depends_on:" "$compose_file" 2>/dev/null || echo "  No explicit depends_on found"

            # Look for network dependencies
            echo "Networks:"
            grep -E "networks:|external_links:" "$compose_file" 2>/dev/null | head -5 || echo "  Default networks"

            # Look for volume dependencies
            echo "Shared volumes:"
            grep -E "volumes_from:|volumes:" "$compose_file" 2>/dev/null | head -5 || echo "  No shared volumes"

            echo ""
          fi
        done
      register: compose_analysis
      changed_when: false
      when: not skip_docker

    - name: Analyze container network connections
      shell: |
        if ! command -v docker >/dev/null 2>&1; then
          echo "Docker not available"
          exit 0
        fi

        echo "=== CONTAINER NETWORK ANALYSIS ==="

        # Get all Docker networks
        echo "Docker Networks:"
        docker network ls --format "table {{.Name}}\t{{.Driver}}\t{{.Scope}}" 2>/dev/null || echo "No networks found"
        echo ""

        # Analyze each network
        networks=$(docker network ls --format "{{.Name}}" 2>/dev/null | grep -v "bridge\|host\|none")

        for network in $networks; do
          echo "=== Network: $network ==="
          containers_in_network=$(docker network inspect "$network" --format '{{range .Containers}}{{.Name}} {{end}}' 2>/dev/null)
          if [ -n "$containers_in_network" ]; then
            echo "Connected containers: $containers_in_network"
          else
            echo "No containers connected"
          fi
          echo ""
        done

        # Check for port conflicts
        echo "=== PORT USAGE ANALYSIS ==="
        docker ps --format "{{.Names}}\t{{.Ports}}" 2>/dev/null | grep -E ":[0-9]+->" | while read line; do
          container=$(echo "$line" | cut -f1)
          ports=$(echo "$line" | cut -f2 | grep -oE "[0-9]+:" | sed 's/://' | sort -n)
          if [ -n "$ports" ]; then
            echo "$container: $(echo $ports | tr '\n' ' ')"
          fi
        done
      register: network_analysis
      changed_when: false
      when: not skip_docker

    - name: Detect service health endpoints
      shell: |
        if ! command -v docker >/dev/null 2>&1; then
          echo "Docker not available"
          exit 0
        fi

        echo "=== HEALTH ENDPOINT DETECTION ==="

        # Common health check patterns
        health_patterns="/health /healthz /ping /status /api/health /health/ready /health/live"

        # Get containers with exposed ports
        docker ps --format "{{.Names}}\t{{.Ports}}" 2>/dev/null | grep -E ":[0-9]+->" | while read line; do
          container=$(echo "$line" | cut -f1)
          ports=$(echo "$line" | cut -f2 | grep -oE "0\.0\.0\.0:[0-9]+" | cut -d: -f2)

          echo "Container: $container"

          for port in $ports; do
            echo "  Port $port:"
            for pattern in $health_patterns; do
              # Test HTTP health endpoint
              if curl -s -f -m 2 "http://localhost:$port$pattern" >/dev/null 2>&1; then
                echo "    ✅ http://localhost:$port$pattern"
                break
              elif curl -s -f -m 2 "https://localhost:$port$pattern" >/dev/null 2>&1; then
                echo "    ✅ https://localhost:$port$pattern"
                break
              fi
            done
          done
          echo ""
        done
      register: health_endpoints
      changed_when: false
      when: not skip_docker
      ignore_errors: yes

    - name: Analyze container resource dependencies
      shell: |
        if ! command -v docker >/dev/null 2>&1; then
          echo "Docker not available"
          exit 0
        fi

        echo "=== RESOURCE DEPENDENCY ANALYSIS ==="

        # Check for containers that might be databases or core services
        echo "Potential Core Services (databases, caches, etc.):"
        docker ps --format "{{.Names}}\t{{.Image}}" 2>/dev/null | grep -iE "(postgres|mysql|mariadb|redis|mongo|elasticsearch|rabbitmq|kafka)" || echo "No obvious database containers found"
        echo ""

        # Check for reverse proxies and load balancers
        echo "Potential Reverse Proxies/Load Balancers:"
        docker ps --format "{{.Names}}\t{{.Image}}" 2>/dev/null | grep -iE "(nginx|apache|traefik|haproxy|caddy)" || echo "No obvious proxy containers found"
        echo ""

        # Check for monitoring services
        echo "Monitoring Services:"
        docker ps --format "{{.Names}}\t{{.Image}}" 2>/dev/null | grep -iE "(prometheus|grafana|influxdb|telegraf|node-exporter)" || echo "No obvious monitoring containers found"
        echo ""

        # Analyze container restart policies
        echo "Container Restart Policies:"
        docker ps -a --format "{{.Names}}" 2>/dev/null | while read container; do
          if [ -n "$container" ]; then
            policy=$(docker inspect "$container" --format '{{.HostConfig.RestartPolicy.Name}}' 2>/dev/null)
            echo "$container: $policy"
          fi
        done
      register: resource_analysis
      changed_when: false
      when: not skip_docker

    - name: Create dependency map
      set_fact:
        dependency_map:
          timestamp: "{{ dependency_timestamp }}"
          hostname: "{{ inventory_hostname }}"
          docker_available: "{{ not skip_docker }}"
          containers:
            running: "{{ running_containers.stdout_lines | default([]) | length }}"
            total: "{{ all_containers.stdout_lines | default([]) | length }}"
          analysis:
            compose_files: "{{ compose_analysis.stdout | default('Docker not available') }}"
            network_topology: "{{ network_analysis.stdout | default('Docker not available') }}"
            health_endpoints: "{{ health_endpoints.stdout | default('Docker not available') }}"
            resource_dependencies: "{{ resource_analysis.stdout | default('Docker not available') }}"

    - name: Display dependency analysis
      debug:
        msg: |

          ==========================================
          🔗 DEPENDENCY ANALYSIS - {{ inventory_hostname }}
          ==========================================

          📊 CONTAINER SUMMARY:
          - Running Containers: {{ dependency_map.containers.running }}
          - Total Containers: {{ dependency_map.containers.total }}
          - Docker Available: {{ dependency_map.docker_available }}

          🐳 COMPOSE FILE ANALYSIS:
          {{ dependency_map.analysis.compose_files }}

          🌐 NETWORK TOPOLOGY:
          {{ dependency_map.analysis.network_topology }}

          🏥 HEALTH ENDPOINTS:
          {{ dependency_map.analysis.health_endpoints }}

          📦 RESOURCE DEPENDENCIES:
          {{ dependency_map.analysis.resource_dependencies }}

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

    - name: Generate dependency report
      copy:
        content: |
          {
            "timestamp": "{{ dependency_map.timestamp }}",
            "hostname": "{{ dependency_map.hostname }}",
            "docker_available": {{ dependency_map.docker_available | lower }},
            "container_summary": {
              "running": {{ dependency_map.containers.running }},
              "total": {{ dependency_map.containers.total }}
            },
            "analysis": {
              "compose_files": {{ dependency_map.analysis.compose_files | to_json }},
              "network_topology": {{ dependency_map.analysis.network_topology | to_json }},
              "health_endpoints": {{ dependency_map.analysis.health_endpoints | to_json }},
              "resource_dependencies": {{ dependency_map.analysis.resource_dependencies | to_json }}
            },
            "recommendations": [
              {% if dependency_map.containers.running > 20 %}
              "Consider implementing container orchestration for {{ dependency_map.containers.running }} containers",
              {% endif %}
              {% if 'No explicit depends_on found' in dependency_map.analysis.compose_files %}
              "Add explicit depends_on relationships to Docker Compose files",
              {% endif %}
              {% if 'No obvious database containers found' not in dependency_map.analysis.resource_dependencies %}
              "Ensure database containers have proper backup and recovery procedures",
              {% endif %}
              "Regular dependency mapping recommended for infrastructure changes"
            ]
          }
        dest: "{{ dependency_report_dir }}/{{ inventory_hostname }}_dependencies_{{ ansible_date_time.epoch }}.json"
      delegate_to: localhost

    - name: Orchestrated container restart (when service_name is provided)
      block:
        - name: Validate service name parameter
          fail:
            msg: "service_name parameter is required for restart operations"
          when: service_name is not defined

        - name: Check if service exists
          shell: |
            if command -v docker >/dev/null 2>&1; then
              docker ps -a --format "{{.Names}}" | grep -x "{{ service_name }}" || echo "not_found"
            else
              echo "docker_not_available"
            fi
          register: service_exists
          changed_when: false

        - name: Fail if service not found
          fail:
            msg: "Service '{{ service_name }}' not found on {{ inventory_hostname }}"
          when: service_exists.stdout == "not_found"

        - name: Get service dependencies (from compose file)
          shell: |
            # Find compose file containing this service
            compose_file=""
            for file in $(find /opt /home -name "docker-compose*.yml" -o -name "compose*.yml" 2>/dev/null); do
              if grep -q "^  {{ service_name }}:" "$file" 2>/dev/null; then
                compose_file="$file"
                break
              fi
            done

            if [ -n "$compose_file" ]; then
              echo "Found in: $compose_file"
              # Extract dependencies
              awk '/^  {{ service_name }}:/,/^  [a-zA-Z]/ {
                if (/depends_on:/) {
                  getline
                  while (/^    - /) {
                    gsub(/^    - /, "")
                    print $0
                    getline
                  }
                }
              }' "$compose_file" 2>/dev/null || echo "no_dependencies"
            else
              echo "no_compose_file"
            fi
          register: service_dependencies
          changed_when: false

        - name: Stop dependent services first
          shell: |
            if [ "{{ service_dependencies.stdout }}" != "no_dependencies" ] && [ "{{ service_dependencies.stdout }}" != "no_compose_file" ]; then
              echo "Stopping dependent services..."
              # This would need to be implemented based on your specific dependency chain
              echo "Dependencies found: {{ service_dependencies.stdout }}"
            fi
          register: stop_dependents
          when: cascade_restart | default(false) | bool

        - name: Restart the target service
          shell: |
            echo "Restarting {{ service_name }}..."
            docker restart "{{ service_name }}"

            # Wait for container to be running
            timeout {{ restart_timeout }} bash -c '
              while [ "$(docker inspect {{ service_name }} --format "{{.State.Status}}" 2>/dev/null)" != "running" ]; do
                sleep 2
              done
            '
          register: restart_result

        - name: Verify service health
          shell: |
            # Wait a moment for service to initialize
            sleep {{ health_check_delay }}

            # Check if container is running
            if [ "$(docker inspect {{ service_name }} --format '{{.State.Status}}' 2>/dev/null)" = "running" ]; then
              echo "✅ Container is running"

              # Try to find and test health endpoint
              ports=$(docker port {{ service_name }} 2>/dev/null | grep -oE "[0-9]+$" | head -1)
              if [ -n "$ports" ]; then
                for endpoint in /health /healthz /ping /status; do
                  if curl -s -f -m 5 "http://localhost:$ports$endpoint" >/dev/null 2>&1; then
                    echo "✅ Health endpoint responding: http://localhost:$ports$endpoint"
                    exit 0
                  fi
                done
                echo "⚠️  No health endpoint found, but container is running"
              else
                echo "⚠️  No exposed ports found, but container is running"
              fi
            else
              echo "❌ Container is not running"
              exit 1
            fi
          register: health_check
          retries: "{{ health_check_retries }}"
          delay: "{{ health_check_delay }}"

        - name: Restart dependent services
          shell: |
            if [ "{{ service_dependencies.stdout }}" != "no_dependencies" ] && [ "{{ service_dependencies.stdout }}" != "no_compose_file" ]; then
              echo "Restarting dependent services..."
              # This would need to be implemented based on your specific dependency chain
              echo "Would restart dependencies: {{ service_dependencies.stdout }}"
            fi
          when: cascade_restart | default(false) | bool

      when: service_name is defined and not skip_docker

    - name: Summary message
      debug:
        msg: |

          🔗 Dependency analysis complete for {{ inventory_hostname }}
          📄 Report saved to: {{ dependency_report_dir }}/{{ inventory_hostname }}_dependencies_{{ ansible_date_time.epoch }}.json

          {% if service_name is defined %}
          🔄 Service restart summary:
          - Target service: {{ service_name }}
          - Restart result: {{ restart_result.rc | default('N/A') }}
          - Health check: {{ 'PASSED' if health_check.rc == 0 else 'FAILED' }}
          {% endif %}

          💡 Use -e service_name=<container_name> to restart specific services
          💡 Use -e cascade_restart=true to restart dependent services
