name: Build Ace3Pro Kernel

on:
  workflow_dispatch:
    inputs:
      enable_susfs:
        description: "Enable susfs support"
        required: false
        default: "true"
        type: boolean
      config_source:
        description: "Choose config source for myconfig"
        required: true
        default: "repo"
        type: choice
        options:
          - repo
      root_solution:
        description: "Choose root solution to integrate"
        required: false
        default: "sukisu"
        type: choice
        options:
          - sukisu
          - kernelsu
          - kernelsu-next
          - none
      lto_solution:
        description: "Select the level of lto"
        required: false
        default: "thin"
        type: choice
        options:
          - thin
          - full    
      kernel_name:
        description: "Custom kernel name (optional)"
        required: false
        default: "GKI"
        type: string

jobs:
  build-kernel:
    runs-on: ubuntu-latest
    env:
      ARCH: arm64
      SUBARCH: arm64
      WORKDIR: ${{ github.workspace }}/kernel
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y \
            bc bison build-essential cpio curl flex \
            git libncurses-dev libssl-dev \
            libelf-dev lzop python3 unzip xz-utils \
            zstd rsync ca-certificates wget \
            pahole dwarves zip gcc g++
          gcc --version

      - name: Setup toolchains & directories
        run: |
          set -e
          echo "WORKDIR=$WORKDIR"
          mkdir -p "$WORKDIR"
          cd "$WORKDIR"

          # 创建目录结构
          mkdir -p clang-r547379
          mkdir -p anykernel3
          mkdir -p output

          # 下载 Clang 工具链
          echo "=== Downloading Clang toolchain ==="
          curl -LO https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86/+archive/refs/heads/master/clang-r547379.tar.gz
          tar -xzf clang-r547379.tar.gz -C clang-r547379
          rm clang-r547379.tar.gz

          # 克隆 GCC 工具链
          echo "=== Cloning GCC toolchains ==="
          git clone https://github.com/LineageOS/android_prebuilts_gcc_linux-x86_aarch64_aarch64-linux-android-4.9 aarch64-linux-android-4.9 --depth=1
          git clone https://github.com/LineageOS/android_prebuilts_gcc_linux-x86_arm_arm-linux-androideabi-4.9 arm-linux-androideabi-4.9 --depth=1

          echo "✅ Setup toolchains -> OK"

      - name: Setup & Clone Kernel
        run: |
          set -e
          mkdir -p "$WORKDIR"
          cd "$WORKDIR"

          # 克隆内核源码
          echo "👉 Cloning kernel source"
          rm -rf android_kernel_oneplus_sm8650
          git clone --depth=1 https://github.com/OPACE3PRO/android_kernel_oneplus_sm8650.git android_kernel_oneplus_sm8650

          # 克隆模块源码
          echo "👉 Cloning sm8650-modules"
          rm -rf sm8650-modules
          git clone --depth=1 https://github.com/OPACE3PRO/android_kernel_oneplus_sm8650-modules.git sm8650-modules

          echo "✅ Kernel source cloned -> android_kernel_oneplus_sm8650"
          echo "✅ Modules cloned -> sm8650-modules"
          echo "=== Directory setup complete ==="
          ls -la "$WORKDIR"
          
          # 设置 KERNEL_DIR 环境变量
          echo "KERNEL_DIR=android_kernel_oneplus_sm8650" >> $GITHUB_ENV

      - name: Copy and configure kernel config
        run: |
          set -euo pipefail
          echo "WORKDIR=$WORKDIR"
          if [ -z "${KERNEL_DIR:-}" ]; then
            echo "KERNEL_DIR is not set. Ensure previous step set it."
            exit 1
          fi

          SRC="$GITHUB_WORKSPACE/config/config_corvette"
          KERNEL_PATH="$WORKDIR/$KERNEL_DIR"
          TARGET_DIR="$KERNEL_PATH/arch/arm64/configs"
          TARGET="$TARGET_DIR/config_defconfig"

          echo "Copying $SRC -> $TARGET"
          if [ ! -f "$SRC" ]; then
            echo "❌ Source config not found: $SRC"
            exit 1
          fi

          mkdir -p "$TARGET_DIR"
          cp -f "$SRC" "$TARGET"

          # 校验目标存在且非空
          if [ -s "$TARGET" ]; then
            echo "✅ OK: $TARGET exists and is non-empty"
            ls -la "$TARGET"
          else
            echo "❌ Error: $TARGET missing or empty"
            exit 1
          fi


      - name: Install root solution
        run: |
          cd "$WORKDIR/$KERNEL_DIR"
          export KCONFIG_CONFIG="$PWD/arch/arm64/configs/config_defconfig"

          echo "👉 选择的 Root 方案：${{ github.event.inputs.root_solution }}"
          case "${{ github.event.inputs.root_solution }}" in
            kernelsu)
              echo "✅ 集成 KernelSU"
              curl -LSs https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh | bash -
              echo "ROOT_SUFFIX=_KernelSU" >> $GITHUB_ENV
              ;;
            kernelsu-next)
              echo "✅ 集成 KernelSU-Next"
              curl -LSs https://raw.githubusercontent.com/KernelSU-Next/KernelSU-Next/next/kernel/setup.sh | bash -
              echo "ROOT_SUFFIX=_KernelSU-Next" >> $GITHUB_ENV
              ;;
            sukisu)
              echo "✅ 集成 SukiSU-Ultra"
              curl -LSs https://raw.githubusercontent.com/SukiSU-Ultra/SukiSU-Ultra/main/kernel/setup.sh | bash -s main
              echo "ROOT_SUFFIX=_SukiSU" >> $GITHUB_ENV
              ;;
            none)
              echo "ℹ️ 未选择任何 Root 方案，跳过"
              ;;
            *)
              echo "❌ 未知的 root_solution: ${{ github.event.inputs.root_solution }}" >&2
              # 默认值，避免未定义时报错
              echo "ROOT_SUFFIX=_NoRoot" >> $GITHUB_ENV
              exit 1
              ;;
          esac

      - name: Apply Susfs patches
        run: |
          if [ "${{ inputs.enable_susfs }}" = "true" ]; then
            cd $GITHUB_WORKSPACE/kernel/android_kernel_oneplus_sm8650

            echo "🌿 Cloning susfs4ksu repository"
            git clone https://gitlab.com/simonpunk/susfs4ksu.git
            cd susfs4ksu
            git checkout origin/gki-android14-6.1

            echo "📁 Copying susfs source and headers"
            cp ./kernel_patches/KernelSU/10_enable_susfs_for_ksu.patch ../KernelSU/
            cp ./kernel_patches/50_add_susfs_in_gki-android14-6.1.patch ../
            cp ./kernel_patches/fs/* ../fs/
            cp ./kernel_patches/include/linux/* ../include/linux/
            cd ../KernelSU

            echo "📦 Applying KernelSU patch"
            patch -p1 --fuzz=3 --ignore-whitespace < 10_enable_susfs_for_ksu.patch || true
            cd ../
            patch -p1 --fuzz=3 --ignore-whitespace < 50_add_susfs_in_gki-android14-6.1.patch || true

            echo "✅ Susfs patch step finished"
          else
            echo "ℹ️ Susfs patches skipped"
          fi


      - name: Build kernel
        run: |
          set -euo pipefail
          cd "$WORKDIR/$KERNEL_DIR"
          echo "=== Build start ==="
          starttime=$(date +'%Y-%m-%d %H:%M:%S')
          echo "Build started at: $starttime"
          
          # 基本变量
          export ARCH=arm64
          export SUBARCH=arm64
          export OUT=out
          export KERNEL_DEFCONFIG=config_defconfig

          # 默认 LTO 为 thin
          export LTO="${{ inputs.lto_solution || 'thin' }}"
          echo "LTO mode: $LTO"

          # 工具链路径
          export CLANG_PATH="$WORKDIR/clang-r547379"
          export GCC64_PATH="$WORKDIR/aarch64-linux-android-4.9"
          export GCC32_PATH="$WORKDIR/arm-linux-androideabi-4.9"

          # 将工具链加入 PATH
          export PATH="${CLANG_PATH}/bin:${GCC64_PATH}/bin:${GCC32_PATH}/bin:${PATH}"

          # CLANG stack frame limit
          export CLANG_MAX_STACK_SIZE=8192
          export KCFLAGS="-Wno-error=frame-larger-than"

          echo "Using CLANG_PATH=$CLANG_PATH"
          which clang || true
          clang --version || true

          # 清理输出目录
          rm -rf "$OUT" && mkdir -p "$OUT"

          # 生成 defconfig
          echo "=== make O=${OUT} ${KERNEL_DEFCONFIG} ==="
          make O=${OUT} ARCH=${ARCH} ${KERNEL_DEFCONFIG}
          if [ $? -ne 0 ]; then
            echo "❌ make ${KERNEL_DEFCONFIG} failed"
            exit 1
          fi

          # 处理 LTO (none/thin/full)
          if [ "${LTO}" = "none" ] || [ "${LTO}" = "thin" ] || [ "${LTO}" = "full" ]; then
            echo "Applying LTO=${LTO} to ${OUT}/.config"
            if [ "${LTO}" = "none" ]; then
              scripts/config --file ${OUT}/.config -d LTO_CLANG -e LTO_NONE -d LTO_CLANG_THIN -d LTO_CLANG_FULL -d THINLTO
            elif [ "${LTO}" = "thin" ]; then
              scripts/config --file ${OUT}/.config -e LTO_CLANG -d LTO_NONE -e LTO_CLANG_THIN -d LTO_CLANG_FULL -e THINLTO
            else
              scripts/config --file ${OUT}/.config -e LTO_CLANG -d LTO_NONE -d LTO_CLANG_THIN -e LTO_CLANG_FULL -d THINLTO
            fi
            grep -E "LTO_CLANG|LTO_NONE|LTO_CLANG_THIN|LTO_CLANG_FULL|THINLTO" ${OUT}/.config || true
          else
            echo "Invalid LTO value: ${LTO}. Use none|thin|full."
            exit 1
          fi

          # 构建参数
          TH_COUNT=$(nproc)
          echo "Using ${TH_COUNT} parallel jobs"
          DEF_ARGS="O=${OUT} \
          ARCH=${ARCH} \
          CROSS_COMPILE=aarch64-linux-gnu- \
          CROSS_COMPILE_COMPAT=arm-linux-gnueabi- \
          CC=${CLANG_PATH}/bin/clang \
          AR=${CLANG_PATH}/bin/llvm-ar \
          NM=${CLANG_PATH}/bin/llvm-nm \
          LD=${CLANG_PATH}/bin/ld.lld \
          HOSTCC=${CLANG_PATH}/bin/clang \
          HOSTCXX=${CLANG_PATH}/bin/clang++ \
          OBJCOPY=${CLANG_PATH}/bin/llvm-objcopy \
          OBJDUMP=${CLANG_PATH}/bin/llvm-objdump \
          READELF=${CLANG_PATH}/bin/llvm-readelf \
          OBJSIZE=${CLANG_PATH}/bin/llvm-size \
          STRIP=${CLANG_PATH}/bin/llvm-strip \
          LLVM_IAS=1 \
          LLVM=1 \
          KCFLAGS=\"${KCFLAGS}\""

          BUILD_ARGS="-j${TH_COUNT} ${DEF_ARGS}"

          echo "=== Start make (logging to ${OUT}/error.log) ==="
          chmod -R 777 *
          rm android/abi_gki_protected_exports_* || true
          make ${BUILD_ARGS} 2>&1 | tee ${OUT}/error.log || true

          echo "=== Tail of build log ==="
          tail -n 200 ${OUT}/error.log || true

          endtime=$(date +'%Y-%m-%d %H:%M:%S')
          echo "Build started at: $starttime"
          echo "Build finished at: $endtime"
          echo "=== Build step finished (check out/error.log for full log) ==="

      - name: Check build results
        run: |
          set -euo pipefail
          cd "$WORKDIR/$KERNEL_DIR"
          echo "=== Build Results ==="
          if [ -f "out/arch/arm64/boot/Image" ]; then
            echo "✅ Kernel build successful!"
            ls -la out/arch/arm64/boot/
            ls -la out/vmlinux || true
            du -h out/arch/arm64/boot/Image || true
          else
            echo "❌ Kernel build failed!"
            echo "=== Last 200 lines of error log ==="
            if [ -f out/error.log ]; then
              tail -n 200 out/error.log
              echo "=== Error summary (last 20 matching lines) ==="
              grep -iE "error|failed|stop" out/error.log | tail -20 || true
            else
              echo "No out/error.log found"
            fi
            exit 1
          fi

      - name: Replace Image in anykernel3
        run: |
          set -e

          WORKDIR=ak3_work
          ZIP_ORIG=anykernel3.zip
          NEW_ZIP=anykernel3-${{ github.run_number }}.zip
          NEW_IMAGE=kernel/${{ env.KERNEL_DIR }}/out/arch/arm64/boot/Image

          # 创建临时工作目录
          rm -rf $WORKDIR
          mkdir -p $WORKDIR
          cd $WORKDIR

          # 解压原刷机包，保持目录结构和权限
          unzip ../$ZIP_ORIG

          # 替换 Image 并设置权限 755
          cp ../$NEW_IMAGE ./Image
          chmod 755 Image

          # 重新打包刷机包
          zip -r ../$NEW_ZIP . -x ".*"

          cd ..

          # 验证新 ZIP 结构
          echo "=== 新刷机包信息 ==="
          zipinfo $NEW_ZIP

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: kernel-build-${{ github.run_number }}${{ env.ROOT_SUFFIX }}
          path: |
              ${{ github.workspace }}/kernel/${{ env.KERNEL_DIR }}/out/arch/arm64/boot/Image*
              ${{ github.workspace }}/kernel/${{ env.KERNEL_DIR }}/out/arch/arm64/boot/dts/*/*.dtb
              ${{ github.workspace }}/kernel/${{ env.KERNEL_DIR }}/out/error.log
              ${{ github.workspace }}/kernel/${{ env.KERNEL_DIR }}/out/.config
              ${{ github.workspace }}/kernel/output/kernel_info.txt

      - name: Upload AnyKernel3 package
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: anykernel3-${{ github.run_number }}${{ env.ROOT_SUFFIX }}
          path: ${{ github.workspace }}/anykernel3-${{ github.run_number }}.zip