---
# Synology Backup Orchestrator
# Coordinates backups across Atlantis/Calypso with integrity verification
# Run with: ansible-playbook -i hosts.ini playbooks/synology_backup_orchestrator.yml --limit synology

- name: Synology Backup Orchestration
  hosts: synology
  gather_facts: yes
  vars:
    backup_retention_days: 30
    critical_containers:
      - "postgres"
      - "mariadb"
      - "gitea"
      - "immich-server"
      - "paperlessngx"
      - "authentik-server"
      - "vaultwarden"

    backup_paths:
      atlantis:
        - "/volume1/docker"
        - "/volume1/media"
        - "/volume1/backups"
        - "/volume1/documents"
      calypso:
        - "/volume1/docker"
        - "/volume1/backups"
        - "/volume1/development"

  tasks:
    - name: Check Synology system status
      shell: |
        echo "=== System Info ==="
        uname -a
        echo "=== Disk Usage ==="
        df -h
        echo "=== Memory Usage ==="
        free -h
        echo "=== Load Average ==="
        uptime
      register: system_status

    - name: Display system status
      debug:
        msg: "{{ system_status.stdout_lines }}"

    - name: Check Docker service status
      shell: systemctl is-active docker
      register: docker_status
      failed_when: false

    - name: Get running containers
      shell: docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"
      register: running_containers
      become: yes

    - name: Identify critical containers
      shell: docker ps --filter "name={{ item }}" --format "{{.Names}}"
      register: critical_container_check
      loop: "{{ critical_containers }}"
      become: yes

    - name: Create backup directory structure
      file:
        path: "/volume1/backups/{{ item }}"
        state: directory
        mode: '0755'
      loop:
        - "containers"
        - "databases"
        - "configs"
        - "logs"
      become: yes

    - name: Stop non-critical containers for backup
      shell: |
        # Get list of running containers excluding critical ones
        critical_pattern="{{ critical_containers | join('|') }}"
        docker ps --format "{{.Names}}" | grep -vE "($critical_pattern)" > /tmp/non_critical_containers.txt || true

        # Stop non-critical containers
        if [ -s /tmp/non_critical_containers.txt ]; then
          echo "Stopping non-critical containers for backup..."
          cat /tmp/non_critical_containers.txt | xargs -r docker stop
          echo "Stopped containers:"
          cat /tmp/non_critical_containers.txt
        else
          echo "No non-critical containers to stop"
        fi
      register: stopped_containers
      when: stop_containers_for_backup | default(false) | bool
      become: yes

    - name: Backup Docker volumes
      shell: |
        backup_date=$(date +%Y%m%d_%H%M%S)
        backup_file="/volume1/backups/containers/docker_volumes_${backup_date}.tar.gz"

        echo "Creating Docker volumes backup: $backup_file"
        tar -czf "$backup_file" -C /volume1/docker . 2>/dev/null || true

        if [ -f "$backup_file" ]; then
          size=$(du -h "$backup_file" | cut -f1)
          echo "Backup created successfully: $backup_file ($size)"
        else
          echo "Backup failed"
          exit 1
        fi
      register: volume_backup
      become: yes

    - name: Backup database containers
      shell: |
        backup_date=$(date +%Y%m%d_%H%M%S)

        # Backup PostgreSQL databases
        for container in $(docker ps --filter "ancestor=postgres" --format "{{.Names}}"); do
          echo "Backing up PostgreSQL container: $container"
          docker exec "$container" pg_dumpall -U postgres > "/volume1/backups/databases/${container}_${backup_date}.sql" 2>/dev/null || true
        done

        # Backup MariaDB databases
        for container in $(docker ps --filter "ancestor=mariadb" --format "{{.Names}}"); do
          echo "Backing up MariaDB container: $container"
          docker exec "$container" mysqldump --all-databases -u root > "/volume1/backups/databases/${container}_${backup_date}.sql" 2>/dev/null || true
        done

        echo "Database backups completed"
      register: database_backup
      become: yes

    - name: Backup container configurations
      shell: |
        backup_date=$(date +%Y%m%d_%H%M%S)
        config_backup="/volume1/backups/configs/container_configs_${backup_date}.tar.gz"

        # Find all docker-compose files and configs
        find /volume1/docker -name "docker-compose.yml" -o -name "*.env" -o -name "config" -type d | \
        tar -czf "$config_backup" -T - 2>/dev/null || true

        if [ -f "$config_backup" ]; then
          size=$(du -h "$config_backup" | cut -f1)
          echo "Configuration backup created: $config_backup ($size)"
        fi
      register: config_backup
      become: yes

    - name: Restart stopped containers
      shell: |
        if [ -f /tmp/non_critical_containers.txt ] && [ -s /tmp/non_critical_containers.txt ]; then
          echo "Restarting previously stopped containers..."
          cat /tmp/non_critical_containers.txt | xargs -r docker start
          echo "Restarted containers:"
          cat /tmp/non_critical_containers.txt
          rm -f /tmp/non_critical_containers.txt
        fi
      when: stop_containers_for_backup | default(false) | bool
      become: yes

    - name: Verify backup integrity
      shell: |
        echo "=== Backup Verification ==="

        # Check volume backup
        latest_volume_backup=$(ls -t /volume1/backups/containers/docker_volumes_*.tar.gz 2>/dev/null | head -1)
        if [ -n "$latest_volume_backup" ]; then
          echo "Volume backup: $latest_volume_backup"
          tar -tzf "$latest_volume_backup" >/dev/null 2>&1 && echo "✓ Volume backup integrity OK" || echo "✗ Volume backup corrupted"
        fi

        # Check database backups
        db_backup_count=$(ls /volume1/backups/databases/*.sql 2>/dev/null | wc -l)
        echo "Database backups: $db_backup_count files"

        # Check config backup
        latest_config_backup=$(ls -t /volume1/backups/configs/container_configs_*.tar.gz 2>/dev/null | head -1)
        if [ -n "$latest_config_backup" ]; then
          echo "Config backup: $latest_config_backup"
          tar -tzf "$latest_config_backup" >/dev/null 2>&1 && echo "✓ Config backup integrity OK" || echo "✗ Config backup corrupted"
        fi
      register: backup_verification
      become: yes

    - name: Clean old backups
      shell: |
        echo "Cleaning backups older than {{ backup_retention_days }} days..."

        # Clean volume backups
        find /volume1/backups/containers -name "docker_volumes_*.tar.gz" -mtime +{{ backup_retention_days }} -delete

        # Clean database backups
        find /volume1/backups/databases -name "*.sql" -mtime +{{ backup_retention_days }} -delete

        # Clean config backups
        find /volume1/backups/configs -name "container_configs_*.tar.gz" -mtime +{{ backup_retention_days }} -delete

        echo "Cleanup completed"
      register: backup_cleanup
      become: yes

    - name: Generate backup report
      copy:
        content: |
          # Synology Backup Report - {{ inventory_hostname }}
          Generated: {{ ansible_date_time.iso8601 }}

          ## System Status
          ```
          {{ system_status.stdout }}
          ```

          ## Running Containers
          ```
          {{ running_containers.stdout }}
          ```

          ## Backup Operations

          ### Volume Backup
          ```
          {{ volume_backup.stdout }}
          ```

          ### Database Backup
          ```
          {{ database_backup.stdout }}
          ```

          ### Configuration Backup
          ```
          {{ config_backup.stdout }}
          ```

          ## Backup Verification
          ```
          {{ backup_verification.stdout }}
          ```

          ## Cleanup Results
          ```
          {{ backup_cleanup.stdout }}
          ```

          ## Critical Containers Status
          {% for container in critical_containers %}
          - {{ container }}: {{ 'Running' if container in running_containers.stdout else 'Not Found' }}
          {% endfor %}
        dest: "/tmp/synology_backup_{{ inventory_hostname }}_{{ ansible_date_time.epoch }}.md"
      delegate_to: localhost

    - name: Display backup summary
      debug:
        msg: |
          Backup Summary for {{ inventory_hostname }}:
          - Volume Backup: {{ 'Completed' if volume_backup.rc == 0 else 'Failed' }}
          - Database Backup: {{ 'Completed' if database_backup.rc == 0 else 'Failed' }}
          - Config Backup: {{ 'Completed' if config_backup.rc == 0 else 'Failed' }}
          - Verification: {{ 'Passed' if backup_verification.rc == 0 else 'Failed' }}
          - Report: /tmp/synology_backup_{{ inventory_hostname }}_{{ ansible_date_time.epoch }}.md
