name: Django CI

on:
  push:
    branches:
      - master
      - dev
    paths-ignore:
      - '**/*.md'
      - '**/*.css'
      - '**/*.js'
  pull_request:
    branches:
      - master
      - dev
    paths-ignore:
      - '**/*.md'
      - '**/*.css'
      - '**/*.js'

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        include:
          # 标准测试 - Python 3.10
          - python-version: "3.10"
            test-type: "standard"
            database: "mysql"
            elasticsearch: false
            coverage: false
            
          # 标准测试 - Python 3.11  
          - python-version: "3.11"
            test-type: "standard" 
            database: "mysql"
            elasticsearch: false
            coverage: false
            
          # 完整测试 - 包含ES和覆盖率
          - python-version: "3.11"
            test-type: "full"
            database: "mysql"
            elasticsearch: true
            coverage: true
            
          # Docker构建测试
          - python-version: "3.11"
            test-type: "docker"
            database: "none"
            elasticsearch: false
            coverage: false

    name: Test (${{ matrix.test-type }}, Python ${{ matrix.python-version }})
    
    steps:
      - name: Checkout代码
        uses: actions/checkout@v4
        
      - name: 设置测试信息
        id: test-info
        run: |
          echo "test_name=${{ matrix.test-type }}-py${{ matrix.python-version }}" >> $GITHUB_OUTPUT
          if [ "${{ matrix.test-type }}" = "docker" ]; then
            echo "skip_python_setup=true" >> $GITHUB_OUTPUT
          else
            echo "skip_python_setup=false" >> $GITHUB_OUTPUT
          fi
          
      # MySQL数据库设置 (只有需要数据库的测试才执行)
      - name: 启动MySQL数据库
        if: matrix.database == 'mysql'
        uses: samin/mysql-action@v1.3
        with:
          host port: 3306
          container port: 3306
          character set server: utf8mb4
          collation server: utf8mb4_general_ci
          mysql version: latest
          mysql root password: root
          mysql database: djangoblog
          mysql user: root
          mysql password: root
          
      # Elasticsearch设置 (只有完整测试才执行)
      - name: 配置系统参数 (ES)
        if: matrix.elasticsearch == true
        run: |
          sudo swapoff -a
          sudo sysctl -w vm.swappiness=1
          sudo sysctl -w fs.file-max=262144
          sudo sysctl -w vm.max_map_count=262144
          
      - name: 启动Elasticsearch
        if: matrix.elasticsearch == true
        uses: miyataka/elasticsearch-github-actions@1
        with:
          stack-version: '7.12.1'
          plugins: 'https://release.infinilabs.com/analysis-ik/stable/elasticsearch-analysis-ik-7.12.1.zip'
          
      # Python环境设置 (Docker测试跳过)
      - name: 设置Python ${{ matrix.python-version }}
        if: steps.test-info.outputs.skip_python_setup == 'false'
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          cache: 'pip'
          cache-dependency-path: 'requirements.txt'
          
      # 多层缓存策略优化
      - name: 缓存Python依赖
        if: steps.test-info.outputs.skip_python_setup == 'false'
        uses: actions/cache@v4
        with:
          path: |
            ~/.cache/pip
            .pytest_cache
          key: ${{ runner.os }}-python-${{ matrix.python-version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('**/pyproject.toml') }}
          restore-keys: |
            ${{ runner.os }}-python-${{ matrix.python-version }}-${{ hashFiles('requirements.txt') }}-
            ${{ runner.os }}-python-${{ matrix.python-version }}-
            ${{ runner.os }}-python-
            
      # Django缓存优化 (测试数据库等)
      - name: 缓存Django资源
        if: matrix.test-type != 'docker'
        uses: actions/cache@v4
        with:
          path: |
            .coverage*
            htmlcov/
            .django_cache/
          key: ${{ runner.os }}-django-${{ matrix.test-type }}-${{ github.sha }}
          restore-keys: |
            ${{ runner.os }}-django-${{ matrix.test-type }}-
            ${{ runner.os }}-django-
            
      - name: 安装Python依赖
        if: steps.test-info.outputs.skip_python_setup == 'false'
        run: |
          echo "📦 安装Python依赖 (Python ${{ matrix.python-version }})"
          python -m pip install --upgrade pip setuptools wheel
          
          # 安装基础依赖
          pip install -r requirements.txt
          
          # 根据测试类型安装额外依赖
          if [ "${{ matrix.coverage }}" = "true" ]; then
            echo "📊 安装覆盖率工具"
            pip install coverage[toml]
          fi
          
          # 验证关键依赖
          echo "🔍 验证关键依赖安装"
          python -c "import django; print(f'Django version: {django.get_version()}')"
          python -c "import MySQLdb; print('MySQL client: OK')" || python -c "import pymysql; print('PyMySQL client: OK')"
          
          if [ "${{ matrix.elasticsearch }}" = "true" ]; then
            python -c "import elasticsearch; print('Elasticsearch client: OK')"
          fi
          
      # Django环境准备
      - name: 准备Django环境
        if: matrix.test-type != 'docker'
        env:
          DJANGO_MYSQL_PASSWORD: root
          DJANGO_MYSQL_HOST: 127.0.0.1
          DJANGO_ELASTICSEARCH_HOST: ${{ matrix.elasticsearch && '127.0.0.1:9200' || '' }}
        run: |
          echo "🔧 准备Django测试环境"
          
          # 等待数据库就绪
          echo "⏳ 等待MySQL数据库启动..."
          for i in {1..30}; do
            if python -c "import MySQLdb; MySQLdb.connect(host='127.0.0.1', user='root', passwd='root', db='djangoblog')" 2>/dev/null; then
              echo "✅ MySQL数据库连接成功"
              break
            fi
            echo "🔄 等待数据库启动... ($i/30)"
            sleep 2
          done
          
          # 等待Elasticsearch就绪 (如果启用)
          if [ "${{ matrix.elasticsearch }}" = "true" ]; then
            echo "⏳ 等待Elasticsearch启动..."
            for i in {1..30}; do
              if curl -s http://127.0.0.1:9200/_cluster/health | grep -q '"status":"green"\|"status":"yellow"'; then
                echo "✅ Elasticsearch连接成功"
                break
              fi
              echo "🔄 等待Elasticsearch启动... ($i/30)"
              sleep 2
            done
          fi
          
      # Django测试执行
      - name: 执行数据库迁移
        if: matrix.test-type != 'docker'
        env:
          DJANGO_MYSQL_PASSWORD: root
          DJANGO_MYSQL_HOST: 127.0.0.1
          DJANGO_ELASTICSEARCH_HOST: ${{ matrix.elasticsearch && '127.0.0.1:9200' || '' }}
        run: |
          echo "🗄️ 执行数据库迁移"
          
          # 检查迁移文件
          echo "📋 检查待应用的迁移..."
          python manage.py showmigrations
          
          # 检查是否有未创建的迁移
          python manage.py makemigrations --check --verbosity 2
          
          # 执行迁移
          python manage.py migrate --verbosity 2
          
          echo "✅ 数据库迁移完成"
          
      - name: 运行Django测试
        if: matrix.test-type != 'docker'
        env:
          DJANGO_MYSQL_PASSWORD: root
          DJANGO_MYSQL_HOST: 127.0.0.1
          DJANGO_ELASTICSEARCH_HOST: ${{ matrix.elasticsearch && '127.0.0.1:9200' || '' }}
        run: |
          echo "🧪 开始执行 ${{ matrix.test-type }} 测试 (Python ${{ matrix.python-version }})"
          
          # 显示Django配置信息
          python manage.py diffsettings | head -20
          
          # 运行测试
          if [ "${{ matrix.coverage }}" = "true" ]; then
            echo "📊 运行测试并生成覆盖率报告"
            coverage run --source='.' --omit='*/venv/*,*/migrations/*,*/tests/*,manage.py' manage.py test --verbosity=2
            
            echo "📈 生成覆盖率报告"
            coverage xml
            coverage report --show-missing
            coverage html
            
            echo "📋 覆盖率统计:"
            coverage report | tail -1
          else
            echo "🧪 运行标准测试"
            python manage.py test --verbosity=2 --failfast
          fi
          
          echo "✅ 测试执行完成"
          
      # 覆盖率报告上传 (只有完整测试才执行)
      - name: 上传覆盖率到Codecov
        if: matrix.coverage == true && success()
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          file: ./coverage.xml
          flags: unittests
          name: codecov-${{ steps.test-info.outputs.test_name }}
          fail_ci_if_error: false
          verbose: true
          
      - name: 上传覆盖率到Codecov (备用)
        if: matrix.coverage == true && failure()
        uses: codecov/codecov-action@v4
        with:
          file: ./coverage.xml
          flags: unittests
          name: codecov-${{ steps.test-info.outputs.test_name }}-fallback
          fail_ci_if_error: false
          verbose: true
          
      # Docker构建测试
      - name: 设置QEMU
        if: matrix.test-type == 'docker'
        uses: docker/setup-qemu-action@v3
        
      - name: 设置Docker Buildx
        if: matrix.test-type == 'docker'
        uses: docker/setup-buildx-action@v3
        
      - name: Docker构建测试
        if: matrix.test-type == 'docker'
        uses: docker/build-push-action@v5
        with:
          context: .
          push: false
          tags: djangoblog/djangoblog:test-${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          
      # 收集测试工件 (失败时收集调试信息)
      - name: 收集测试工件
        if: failure() && matrix.test-type != 'docker'
        run: |
          echo "🔍 收集测试失败的调试信息"
          
          # 收集Django日志
          if [ -d "logs" ]; then
            echo "📄 Django日志文件:"
            ls -la logs/
            if [ -f "logs/djangoblog.log" ]; then
              echo "🔍 最新日志内容:"
              tail -100 logs/djangoblog.log
            fi
          fi
          
          # 显示数据库状态
          echo "🗄️ 数据库连接状态:"
          python -c "
          try:
              from django.db import connection
              cursor = connection.cursor()
              cursor.execute('SELECT VERSION()')
              print(f'MySQL版本: {cursor.fetchone()[0]}')
              cursor.execute('SHOW TABLES')
              tables = cursor.fetchall()
              print(f'数据库表数量: {len(tables)}')
          except Exception as e:
              print(f'数据库连接错误: {e}')
          " || true
          
          # Elasticsearch状态 (如果启用)
          if [ "${{ matrix.elasticsearch }}" = "true" ]; then
            echo "🔍 Elasticsearch状态:"
            curl -s http://127.0.0.1:9200/_cluster/health?pretty || true
          fi
          
      # 上传测试工件
      - name: 上传覆盖率HTML报告
        if: matrix.coverage == true && always()
        uses: actions/upload-artifact@v4
        with:
          name: coverage-report-${{ steps.test-info.outputs.test_name }}
          path: htmlcov/
          retention-days: 30
          
      # 性能统计
      - name: 测试性能统计
        if: always() && matrix.test-type != 'docker'
        run: |
          echo "⚡ 测试性能统计:"
          echo "   开始时间: $(date -d '@${{ job.started_at }}' '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo '未知')"
          echo "   当前时间: $(date '+%Y-%m-%d %H:%M:%S')"
          
          # 系统资源使用情况
          echo "💻 系统资源:"
          echo "   CPU使用: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)%"
          echo "   内存使用: $(free -h | awk '/^Mem:/ {printf "%.1f%%", $3/$2 * 100}')"
          echo "   磁盘使用: $(df -h / | awk 'NR==2{printf "%s", $5}')"
          
      # 测试结果汇总
      - name: 测试完成总结
        if: always()
        run: |
          echo "📋 ============ 测试执行总结 ============"
          echo "   🏷️  测试类型: ${{ matrix.test-type }}"
          echo "   🐍 Python版本: ${{ matrix.python-version }}"
          echo "   🗄️  数据库: ${{ matrix.database }}"
          echo "   🔍 Elasticsearch: ${{ matrix.elasticsearch }}"
          echo "   📊 覆盖率: ${{ matrix.coverage }}"
          echo "   ⚡ 状态: ${{ job.status }}"
          echo "   📅 完成时间: $(date '+%Y-%m-%d %H:%M:%S')"
          echo "============================================"
          
          # 根据测试结果显示不同消息
          if [ "${{ job.status }}" = "success" ]; then
            echo "🎉 测试执行成功！"
          else
            echo "❌ 测试执行失败，请检查上面的日志"
          fi
