name: PyPI Publishing

on:
  workflow_dispatch:
    inputs:
      release_type:
        description: 'Type of release'
        required: true
        default: 'manual'
        type: choice
        options:
          - manual
          - security-driven
      release_notes:
        description: 'Release notes or justification'
        required: false
        type: string
      dry_run:
        description: 'Perform dry run (build only, no publish)'
        required: false
        default: false
        type: boolean

permissions:
  contents: read           # Required for repository checkout and access
  security-events: write  # Required for security report uploads
  actions: read           # Required for workflow status checks

env:
  PYTHON_VERSION: '3.12'

jobs:
  quality-gates:
    name: Quality Gates Validation
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ env.PYTHON_VERSION }}
      
      - name: Install UV
        run: |
          curl -LsSf https://astral.sh/uv/install.sh | sh
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH
          source $HOME/.cargo/env
      
      - name: Install dependencies
        run: |
          export PATH="$HOME/.cargo/bin:$PATH"
          uv sync
      
      - name: Run quality gate checks
        run: |
          export PATH="$HOME/.cargo/bin:$PATH"
          ./scripts/run_tests.sh
        env:
          GITHUB_REPOSITORY: ${{ github.repository }}
          PYPI_PACKAGE: mypylogger
      
      - name: Quality gates summary
        if: always()
        run: |
          echo "Quality Gates Status: ${{ job.status }}"
          if [ "${{ job.status }}" = "success" ]; then
            echo "✅ All quality gates passed - proceeding to package building"
          else
            echo "❌ Quality gates failed - cannot proceed with publishing"
            exit 1
          fi

  package-validation:
    name: Package Validation and Building
    runs-on: ubuntu-latest
    needs: quality-gates
    
    outputs:
      package-version: ${{ steps.extract-version.outputs.version }}
      package-name: ${{ steps.extract-version.outputs.name }}
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ env.PYTHON_VERSION }}
      
      - name: Install UV and build tools
        run: |
          curl -LsSf https://astral.sh/uv/install.sh | sh
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH
          source $HOME/.cargo/env
      
      - name: Install dependencies and build tools
        run: |
          export PATH="$HOME/.cargo/bin:$PATH"
          uv sync
          uv add --dev build twine
      
      - name: Extract package metadata
        id: extract-version
        run: |
          export PATH="$HOME/.cargo/bin:$PATH"
          VERSION=$(uv run python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
          NAME=$(uv run python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['name'])")
          echo "version=$VERSION" >> $GITHUB_OUTPUT
          echo "name=$NAME" >> $GITHUB_OUTPUT
          echo "Package: $NAME v$VERSION"
      
      - name: Validate package configuration
        run: |
          export PATH="$HOME/.cargo/bin:$PATH"
          echo "🔍 Validating package configuration..."
          
          # Check required fields in pyproject.toml
          uv run python -c "
          import tomllib
          import sys
          
          with open('pyproject.toml', 'rb') as f:
              config = tomllib.load(f)
          
          project = config.get('project', {})
          required_fields = ['name', 'version', 'description', 'authors']
          
          missing = [field for field in required_fields if not project.get(field)]
          if missing:
              print(f'❌ Missing required fields: {missing}')
              sys.exit(1)
          
          print('✅ Package configuration is valid')
          "
      
      - name: Build source distribution
        run: |
          export PATH="$HOME/.cargo/bin:$PATH"
          echo "🏗️ Building source distribution..."
          uv run python -m build --sdist
          
          # Verify sdist was created
          if [ ! -f "dist/${{ steps.extract-version.outputs.name }}-${{ steps.extract-version.outputs.version }}.tar.gz" ]; then
            echo "❌ Source distribution build failed"
            exit 1
          fi
          echo "✅ Source distribution built successfully"
      
      - name: Build wheel distribution
        run: |
          export PATH="$HOME/.cargo/bin:$PATH"
          echo "🏗️ Building wheel distribution..."
          uv run python -m build --wheel
          
          # Verify wheel was created
          if [ ! -f "dist/${{ steps.extract-version.outputs.name }}-${{ steps.extract-version.outputs.version }}-py3-none-any.whl" ]; then
            echo "❌ Wheel distribution build failed"
            exit 1
          fi
          echo "✅ Wheel distribution built successfully"
      
      - name: Validate package integrity
        run: |
          export PATH="$HOME/.cargo/bin:$PATH"
          echo "🔍 Validating package integrity..."
          
          # Check package contents
          uv run twine check dist/*
          
          # Verify package can be installed
          echo "Testing package installation..."
          uv run pip install dist/${{ steps.extract-version.outputs.name }}-${{ steps.extract-version.outputs.version }}-py3-none-any.whl
          
          # Test basic import
          uv run python -c "
          try:
              import mypylogger
              print('✅ Package imports successfully')
          except ImportError as e:
              print(f'❌ Package import failed: {e}')
              exit(1)
          "
      
      - name: Generate package metadata
        run: |
          export PATH="$HOME/.cargo/bin:$PATH"
          echo "📋 Generating package metadata..."
          
          # Create metadata file
          cat > package-metadata.json << EOF
          {
            "name": "${{ steps.extract-version.outputs.name }}",
            "version": "${{ steps.extract-version.outputs.version }}",
            "release_type": "${{ github.event.inputs.release_type }}",
            "release_notes": "${{ github.event.inputs.release_notes }}",
            "build_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
            "commit_sha": "${{ github.sha }}",
            "workflow_run": "${{ github.run_id }}"
          }
          EOF
          
          echo "Package metadata:"
          cat package-metadata.json
      
      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: python-package-distributions
          path: |
            dist/
            package-metadata.json
          retention-days: 30

  publish-to-pypi:
    name: Publish to PyPI
    runs-on: ubuntu-latest
    needs: [quality-gates, package-validation]
    if: ${{ !inputs.dry_run }}
    environment: pypi-publishing
    
    # Required for AWS OIDC authentication
    permissions:
      id-token: write
      contents: read
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Download build artifacts
        uses: actions/download-artifact@v4
        with:
          name: python-package-distributions
      
      - name: Validate AWS OIDC configuration
        run: |
          echo "🔍 Validating AWS OIDC configuration before authentication..."
          python scripts/validate_aws_config.py
        env:
          AWS_REGION: ${{ secrets.AWS_REGION || 'us-east-1' }}
          AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }}
          AWS_SECRET_NAME: ${{ secrets.AWS_SECRET_NAME }}
      
      - name: Display package information
        run: |
          echo "📦 Publishing package to PyPI..."
          echo "Package: ${{ needs.package-validation.outputs.package-name }} v${{ needs.package-validation.outputs.package-version }}"
          echo "Release Type: ${{ github.event.inputs.release_type }}"
          echo "Release Notes: ${{ github.event.inputs.release_notes }}"
          
          echo "Built distributions:"
          ls -la dist/
          
          echo "Package metadata:"
          cat package-metadata.json
      
      - name: Configure AWS OIDC authentication (Attempt 1)
        id: aws-auth-1
        uses: aws-actions/configure-aws-credentials@v4
        continue-on-error: true
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: ${{ secrets.AWS_REGION || 'us-east-1' }}
          role-session-name: GitHubActions-PyPI-Publishing
          role-duration-seconds: 900  # 15 minutes
        env:
          AWS_RETRY_MODE: adaptive
          AWS_MAX_ATTEMPTS: 3
      
      - name: Wait and retry AWS authentication (Attempt 2)
        if: steps.aws-auth-1.outcome == 'failure'
        run: |
          echo "⏳ First AWS authentication attempt failed, waiting 2 seconds before retry..."
          sleep 2
      
      - name: Configure AWS OIDC authentication (Attempt 2)
        id: aws-auth-2
        if: steps.aws-auth-1.outcome == 'failure'
        uses: aws-actions/configure-aws-credentials@v4
        continue-on-error: true
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: ${{ secrets.AWS_REGION || 'us-east-1' }}
          role-session-name: GitHubActions-PyPI-Publishing
          role-duration-seconds: 900  # 15 minutes
        env:
          AWS_RETRY_MODE: adaptive
          AWS_MAX_ATTEMPTS: 3
      
      - name: Wait and retry AWS authentication (Attempt 3)
        if: steps.aws-auth-1.outcome == 'failure' && steps.aws-auth-2.outcome == 'failure'
        run: |
          echo "⏳ Second AWS authentication attempt failed, waiting 4 seconds before final retry..."
          sleep 4
      
      - name: Configure AWS OIDC authentication (Attempt 3 - Final)
        id: aws-auth-3
        if: steps.aws-auth-1.outcome == 'failure' && steps.aws-auth-2.outcome == 'failure'
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: ${{ secrets.AWS_REGION || 'us-east-1' }}
          role-session-name: GitHubActions-PyPI-Publishing
          role-duration-seconds: 900  # 15 minutes
        env:
          AWS_RETRY_MODE: adaptive
          AWS_MAX_ATTEMPTS: 3
      
      - name: AWS authentication summary
        run: |
          echo "📊 AWS Authentication Summary:"
          if [ "${{ steps.aws-auth-1.outcome }}" = "success" ]; then
            echo "  ✅ Succeeded on attempt 1"
          elif [ "${{ steps.aws-auth-2.outcome }}" = "success" ]; then
            echo "  ✅ Succeeded on attempt 2 (after 2s backoff)"
          elif [ "${{ steps.aws-auth-3.outcome }}" = "success" ]; then
            echo "  ✅ Succeeded on attempt 3 (after 4s backoff)"
          else
            echo "  ❌ Failed after 3 attempts with exponential backoff"
            exit 1
          fi
      
      - name: Log AWS authentication details
        run: |
          echo "📋 AWS Authentication Details:"
          echo "  Region: ${{ secrets.AWS_REGION || 'us-east-1' }}"
          echo "  Session: GitHubActions-PyPI-Publishing"
          echo "  Duration: 900 seconds (15 minutes)"
          echo "  Retry Mode: adaptive"
          echo "  Max Attempts: 3"
      
      - name: Verify AWS authentication and connectivity
        run: |
          echo "🔐 Verifying AWS OIDC authentication..."
          
          # Verify AWS credentials are working
          aws sts get-caller-identity
          
          # Test access to secrets manager
          aws secretsmanager describe-secret --secret-id ${{ secrets.AWS_SECRET_NAME }} --query 'Name' --output text
          
          echo "✅ AWS authentication successful"
      
      - name: Retrieve PyPI token from AWS Secrets Manager
        id: get-pypi-token
        run: |
          echo "🔑 Retrieving PyPI token from AWS Secrets Manager..."
          
          # Retrieve the secret with error handling
          SECRET_JSON=$(aws secretsmanager get-secret-value \
            --secret-id ${{ secrets.AWS_SECRET_NAME }} \
            --query 'SecretString' \
            --output text)
          
          if [ -z "$SECRET_JSON" ]; then
            echo "❌ Failed to retrieve secret from AWS Secrets Manager"
            exit 1
          fi
          
          # Parse the JSON and extract the token
          PYPI_TOKEN=$(echo "$SECRET_JSON" | jq -r '.token')
          
          if [ -z "$PYPI_TOKEN" ] || [ "$PYPI_TOKEN" = "null" ]; then
            echo "❌ PyPI token not found in secret"
            exit 1
          fi
          
          # Validate token format
          if [[ ! "$PYPI_TOKEN" =~ ^pypi-.+ ]]; then
            echo "❌ Invalid PyPI token format"
            exit 1
          fi
          
          # Set token as masked output
          echo "::add-mask::$PYPI_TOKEN"
          echo "pypi_token=$PYPI_TOKEN" >> $GITHUB_OUTPUT
          
          echo "✅ PyPI token retrieved successfully"
      
      - name: Set up Python for publishing
        uses: actions/setup-python@v5
        with:
          python-version: ${{ env.PYTHON_VERSION }}
      
      - name: Install UV and publishing tools
        run: |
          curl -LsSf https://astral.sh/uv/install.sh | sh
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH
          source $HOME/.cargo/env
          
          export PATH="$HOME/.cargo/bin:$PATH"
          uv sync
          uv add --dev twine
      
      - name: Publish to PyPI with OIDC authentication
        run: |
          export PATH="$HOME/.cargo/bin:$PATH"
          echo "🚀 Publishing to PyPI with AWS OIDC authentication..."
          
          # Run publishing script with OIDC authentication
          uv run python scripts/publish_with_error_handling.py \
            --package-dir . \
            --log-file publishing.log \
            --report-file publishing_report.json \
            --pypi-token "${{ steps.get-pypi-token.outputs.pypi_token }}" \
            --auth-method "oidc" \
            ${{ inputs.dry_run && '--dry-run' || '' }}
          
          # Display publishing report
          if [ -f "publishing_report.json" ]; then
            echo "📊 Publishing Report:"
            cat publishing_report.json | jq '.'
          fi
          
          # Display log file if it exists
          if [ -f "publishing.log" ]; then
            echo "📋 Publishing Log (last 50 lines):"
            tail -50 publishing.log
          fi
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ steps.get-pypi-token.outputs.pypi_token }}
      
      - name: Update live security status after publishing
        run: |
          export PATH="$HOME/.cargo/bin:$PATH"
          echo "📊 Updating live security status after successful publishing..."
          
          # Execute manual workflow to update status
          uv run python scripts/integration_orchestrator.py manual-workflow \
            --notes="Published ${{ needs.package-validation.outputs.package-name }} v${{ needs.package-validation.outputs.package-version }} to PyPI"
          
          echo "✅ Live security status updated"
      
      - name: Create release summary
        run: |
          cat > release-summary.md << EOF
          # PyPI Release Summary
          
          ## Package Information
          - **Name**: ${{ needs.package-validation.outputs.package-name }}
          - **Version**: ${{ needs.package-validation.outputs.package-version }}
          - **Release Type**: ${{ github.event.inputs.release_type }}
          - **Build Date**: $(date -u +%Y-%m-%dT%H:%M:%SZ)
          
          ## Release Notes
          ${{ github.event.inputs.release_notes }}
          
          ## Quality Gates
          - ✅ All tests passed
          - ✅ Code quality checks passed
          - ✅ Security scans passed
          - ✅ Package integrity validated
          
          ## Distribution Files
          $(ls -la dist/)
          
          ## Live Status
          - ✅ Security status updated
          - 📊 Status available at GitHub Pages
          
          ## Next Steps
          - Package is available on PyPI
          - Update documentation if needed
          - Monitor for any issues
          EOF
          
          echo "Release summary:"
          cat release-summary.md
      
      - name: Handle publishing failure
        if: failure()
        run: |
          export PATH="$HOME/.cargo/bin:$PATH"
          echo "🚨 Publishing failed - sending failure notifications..."
          
          # Send failure notifications
          if [ -f "publishing_report.json" ]; then
            uv run python scripts/notify_publishing_failure.py \
              --error-report publishing_report.json \
              --create-issue
          else
            echo "⚠️  No publishing report found - cannot send detailed notifications"
          fi
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      
      - name: Upload release artifacts
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: release-artifacts
          path: |
            release-summary.md
            publishing_report.json
            publishing.log
          if-no-files-found: ignore

  dry-run-summary:
    name: Dry Run Summary
    runs-on: ubuntu-latest
    needs: [quality-gates, package-validation]
    if: ${{ inputs.dry_run }}
    
    steps:
      - name: Download build artifacts
        uses: actions/download-artifact@v4
        with:
          name: python-package-distributions
      
      - name: Display dry run results
        run: |
          echo "🧪 Dry Run Complete - No Publishing Performed"
          echo "================================================"
          echo ""
          echo "Package: ${{ needs.package-validation.outputs.package-name }} v${{ needs.package-validation.outputs.package-version }}"
          echo "Release Type: ${{ github.event.inputs.release_type }}"
          echo ""
          echo "✅ Quality Gates: PASSED"
          echo "✅ Package Building: PASSED"
          echo "✅ Package Validation: PASSED"
          echo ""
          echo "Built distributions:"
          ls -la dist/
          echo ""
          echo "Package metadata:"
          cat package-metadata.json
          echo ""
          echo "🚀 Ready for publishing when dry_run=false"

  workflow-summary:
    name: Workflow Summary
    runs-on: ubuntu-latest
    needs: [quality-gates, package-validation, publish-to-pypi, dry-run-summary]
    if: always()
    
    steps:
      - name: Generate workflow summary
        run: |
          echo "# PyPI Publishing Workflow Summary" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          
          if [ "${{ needs.quality-gates.result }}" = "success" ]; then
            echo "✅ **Quality Gates**: All checks passed" >> $GITHUB_STEP_SUMMARY
          else
            echo "❌ **Quality Gates**: Failed" >> $GITHUB_STEP_SUMMARY
          fi
          
          if [ "${{ needs.package-validation.result }}" = "success" ]; then
            echo "✅ **Package Building**: Successful" >> $GITHUB_STEP_SUMMARY
          else
            echo "❌ **Package Building**: Failed" >> $GITHUB_STEP_SUMMARY
          fi
          
          if [ "${{ inputs.dry_run }}" = "true" ]; then
            echo "🧪 **Mode**: Dry run (no publishing)" >> $GITHUB_STEP_SUMMARY
          elif [ "${{ needs.publish-to-pypi.result }}" = "success" ]; then
            echo "🚀 **Publishing**: Successful" >> $GITHUB_STEP_SUMMARY
          elif [ "${{ needs.publish-to-pypi.result }}" = "failure" ]; then
            echo "❌ **Publishing**: Failed" >> $GITHUB_STEP_SUMMARY
          else
            echo "⏭️ **Publishing**: Skipped" >> $GITHUB_STEP_SUMMARY
          fi
          
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "**Package**: ${{ needs.package-validation.outputs.package-name }} v${{ needs.package-validation.outputs.package-version }}" >> $GITHUB_STEP_SUMMARY
          echo "**Release Type**: ${{ github.event.inputs.release_type }}" >> $GITHUB_STEP_SUMMARY