name: Docker Build Tests

on:
  push:
    branches: [ "main" ]
    paths:
      - 'apps/server/**'
      - 'dockerfiles/**'
      - 'docker-compose.yml'
      - 'install.sh'
      - '.github/workflows/docker-build.yml'
  pull_request:
    branches: [ "main" ]
    paths:
      - 'apps/server/**'
      - 'dockerfiles/**'
      - 'docker-compose.yml'
      - 'install.sh'
      - '.github/workflows/docker-build.yml'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  docker-all-in-one-build:
    name: Docker All-in-One Build Test
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - name: Build all-in-one Docker image
        run: |
          docker build -f dockerfiles/all-in-one/Dockerfile -t aliasvault-allinone:test .
          echo "✅ All-in-one Docker image built successfully"

      - name: Run all-in-one container
        run: |
          docker run -d \
            --name aliasvault-test \
            -p 8080:80 \
            -p 8443:443 \
            -p 2525:25 \
            -p 2587:587 \
            -v "$(pwd)/database:/database" \
            -v "$(pwd)/certificates:/certificates" \
            -v "$(pwd)/logs:/logs" \
            -v "$(pwd)/secrets:/secrets" \
            aliasvault-allinone:test

      - name: Wait for services to be ready
        run: |
          echo "Waiting for services to initialize..."
          for i in {1..60}; do
            if docker exec aliasvault-test curl -f http://localhost:3001/api 2>/dev/null; then
              echo "✅ API service is ready"
              break
            fi
            echo "Waiting for services... ($i/60)"
            sleep 5
          done

      - name: Check container logs if needed
        if: failure()
        run: docker logs aliasvault-test

      - name: Test root endpoint
        uses: nick-fields/retry@v3
        with:
          timeout_minutes: 2
          max_attempts: 3
          command: |
            http_code=$(curl -k -s -o /dev/null -w "%{http_code}" https://localhost:8443/)
            if [ "$http_code" -ne 200 ]; then
              echo "❌ Root endpoint (/) failed with HTTP $http_code"
              docker logs aliasvault-test
              exit 1
            fi
            echo "✅ Root endpoint (/) returned HTTP 200"

      - name: Test API endpoint
        uses: nick-fields/retry@v3
        with:
          timeout_minutes: 2
          max_attempts: 3
          command: |
            http_code=$(curl -k -s -o /dev/null -w "%{http_code}" https://localhost:8443/api)
            if [ "$http_code" -ne 200 ]; then
              echo "❌ API endpoint (/api) failed with HTTP $http_code"
              docker logs aliasvault-test
              exit 1
            fi
            echo "✅ API endpoint (/api) returned HTTP 200"

      - name: Test Admin endpoint
        uses: nick-fields/retry@v3
        with:
          timeout_minutes: 2
          max_attempts: 3
          command: |
            http_code=$(curl -k -s -o /dev/null -w "%{http_code}" https://localhost:8443/admin/user/login)
            if [ "$http_code" -ne 200 ]; then
              echo "❌ Admin endpoint (/admin) failed with HTTP $http_code"
              docker logs aliasvault-test
              exit 1
            fi
            echo "✅ Admin endpoint (/admin) returned HTTP 200"

      - name: Verify admin password hash file does not exist initially
        run: |
          if [ -f "./secrets/admin_password_hash" ]; then
            echo "❌ Admin password hash file should not exist initially"
            cat ./secrets/admin_password_hash
            exit 1
          fi
          echo "✅ Admin password hash file correctly does not exist initially"

      - name: Test admin password reset flow
        run: |
          echo "🔧 Testing admin password reset flow..."

          # Run the reset password script with auto-confirm
          echo "Running reset-admin-password command..."
          password_output=$(docker exec aliasvault-test aliasvault reset-admin-password -y 2>&1)
          echo "Script output:"
          echo "$password_output"

          # Extract the generated password from the output
          generated_password=$(echo "$password_output" | grep -E "^Password: " | sed 's/Password: //')
          if [ -z "$generated_password" ]; then
            echo "❌ Failed to extract generated password from script output"
            echo "Full output was:"
            echo "$password_output"
            exit 1
          fi
          echo "✅ Generated password extracted: $generated_password"

          # Verify that the admin_password_hash file now exists in the container
          if ! docker exec aliasvault-test test -f /secrets/admin_password_hash; then
            echo "❌ Admin password hash file was not created in container"
            docker exec aliasvault-test ls -la /secrets/
            exit 1
          fi
          echo "✅ Admin password hash file created in container"

          # Verify that the admin_password_hash file exists locally (mounted volume)
          if [ ! -f "./secrets/admin_password_hash" ]; then
            echo "❌ Admin password hash file not found in local secrets folder"
            ls -la ./secrets/
            exit 1
          fi
          echo "✅ Admin password hash file exists in local secrets folder"

      - name: Test SMTP port
        uses: nick-fields/retry@v3
        with:
          timeout_minutes: 2
          max_attempts: 3
          command: |
            if ! nc -zv localhost 2525 2>&1 | grep -q 'succeeded'; then
              echo "❌ SMTP port 2525 is not accessible"
              docker logs aliasvault-test
              exit 1
            fi
            echo "✅ SMTP port 2525 is accessible"

      - name: Cleanup
        if: always()
        run: |
          docker stop aliasvault-test || true
          docker rm aliasvault-test || true

  docker-compose-build:
    name: Docker Compose Build Test
    runs-on: ubuntu-latest

    services:
      docker:
        image: docker:26.0.0
        options: --privileged

    steps:
      - uses: actions/checkout@v2

      - name: Check local docker-compose.yml for :latest tags
        run: |
          # Check for explicit version tags instead of :latest
          if grep -E "ghcr\.io/aliasvault/[^:]+:[0-9]+\.[0-9]+\.[0-9]+" docker-compose.yml; then
            echo "❌ Error: docker-compose.yml contains explicit version tags instead of :latest"
            echo "Found the following explicit versions:"
            grep -E "ghcr\.io/aliasvault/[^:]+:[0-9]+\.[0-9]+\.[0-9]+" docker-compose.yml
            echo ""
            echo "All AliasVault images in docker-compose.yml must use ':latest' tags, not explicit versions."
            echo "Please update docker-compose.yml to use ':latest' for all AliasVault images."
            exit 1
          fi

          echo "✅ docker-compose.yml correctly uses :latest tags for all AliasVault images"

      - name: Create .env file with custom SMTP port
        run: echo "SMTP_PORT=2525" > .env

      - name: Set permissions and run install.sh build
        run: |
          chmod +x install.sh
          ./install.sh build --verbose

      - name: Test services are responding
        uses: nick-fields/retry@v3
        with:
          timeout_minutes: 5
          max_attempts: 5
          command: |
            sleep 15
            declare -A endpoints=(
              ["WASM"]="https://localhost:443"
              ["WebApi"]="https://localhost:443/api"
              ["Admin"]="https://localhost:443/admin/user/login"
            )
            failed=false
            for name in "${!endpoints[@]}"; do
              url="${endpoints[$name]}"
              echo "Testing $name at $url"
              response=$(curl -k -s -w "\nHTTP_CODE=%{http_code}" "$url")
              http_code=$(echo "$response" | grep "HTTP_CODE=" | cut -d= -f2)
              if [ "$http_code" -ne 200 ]; then
                echo "❌ $name failed with $http_code"
                failed=true
              else
                echo "✅ $name passed"
              fi
            done

            echo "Testing SMTP on port 2525"
            if ! nc -zv localhost 2525 2>&1 | grep -q 'succeeded'; then
              echo "❌ SMTP failed"
              failed=true
            else
              echo "✅ SMTP passed"
            fi

            if [ "$failed" = true ]; then
              echo "Dumping logs"
              docker compose logs admin
              docker compose logs api
              docker compose logs client
              docker compose logs smtp
              docker compose logs reverse-proxy
              docker compose restart
              exit 1
            fi

      - name: Test reset-admin-password output
        if: ${{ !steps.install_script.outputs.skip_remaining }}
        run: |
          output=$(./install.sh reset-admin-password | sed 's/\x1b\[[0-9;]*m//g')
          if ! echo "$output" | grep -Eq '^\s*Password: [A-Za-z0-9+/=]{8,}'; then
            echo "Invalid reset-admin-password output"
            exit 1
          fi
