using InteractiveUtils
versioninfo(;verbose=true)

const JET_PROJECT = normpath(joinpath(@__DIR__, "projects", "jet"))
const test_args = isempty(ARGS) ? ["general"] : ARGS
const JET_flag = length(test_args) == 1 && startswith(only(test_args), "jet")

if JET_flag
    @info "Activating the dedicated JET test environment." project=JET_PROJECT
    using Pkg
    Pkg.activate(JET_PROJECT)
    Pkg.instantiate()
end

CUDA_flag = false
ROCm_flag = false
OpenCL_flag = false
Oscar_flag = false
Tesseract_flag = false

if Sys.iswindows() || Sys.ARCH != :x86_64
    @info "Skipping Oscar tests -- only supported x86_64 *NIX platforms."
else
    Oscar_flag = VERSION >= v"1.11"
    !Oscar_flag && @info "Skipping Oscar tests -- not tested on Julia < 1.11"
end

if Sys.iswindows()
    @info "Skipping Tesseract tests -- only supported *NIX platforms."
else
    Tesseract_flag = true
end

if Sys.iswindows()
    @info "Skipping GPU/OpenCL tests -- only executed on *NIX platforms."
else
    CUDA_flag = get(ENV, "GPU_TEST", "") == "cuda"
    ROCm_flag = get(ENV, "GPU_TEST", "") == "rocm"
    OpenCL_flag = get(ENV, "GPU_TEST", "") == "opencl"

    CUDA_flag && @info "Running with CUDA tests."
    ROCm_flag && @info "Running with ROCm tests."
    OpenCL_flag && @info "Running with OpenCL tests."
    if !any((CUDA_flag, ROCm_flag, OpenCL_flag))
        @info "Skipping GPU/OpenCL tests -- must be explicitly enabled."
        @info "Environment must uniquely set GPU_TEST=cuda/rocm/opencl."
    end
end

using Pkg
CUDA_flag && Pkg.add("CUDA")
ROCm_flag && Pkg.add("AMDGPU")
OpenCL_flag && Pkg.add(["pocl_jll", "OpenCL"])
if any((CUDA_flag, ROCm_flag, OpenCL_flag))
    Pkg.add(
        ["Adapt", "Atomix", "GPUArraysCore", "GPUArrays", "KernelAbstractions"]
    )
end
!JET_flag && Oscar_flag && Pkg.add("Oscar")
!JET_flag && Tesseract_flag && Pkg.add("PyTesseractDecoder")


using TestItemRunner
using QuantumClifford

# filter for the test
testfilter = ti -> begin
    exclude = Symbol[]

    if JET_flag
        return :jet in ti.tags
    else
        push!(exclude, :jet)
    end

    if !Oscar_flag
        push!(exclude, :oscar_required)
    end

    if !Tesseract_flag
        push!(exclude, :tesseract_required)
    end

    if get(ENV, "ECC_TEST", "") == "base"
        return (:ecc in ti.tags) && (:ecc_base in ti.tags) && all(!in(exclude), ti.tags)

    elseif get(ENV, "ECC_TEST", "") == "encoding"
        return (:ecc in ti.tags) && (:ecc_encoding in ti.tags) && all(!in(exclude), ti.tags)

    elseif get(ENV, "ECC_TEST", "") == "decoding"
        return (:ecc in ti.tags) && (:ecc_decoding in ti.tags) && all(!in(exclude), ti.tags)

    elseif get(ENV, "ECC_TEST", "") == "syndromecircuit"
        return (:ecc in ti.tags) && (:ecc_syndrome_circuit_equivalence in ti.tags) && all(!in(exclude), ti.tags)

    elseif get(ENV, "ECC_TEST", "") == "syndromemeasurement"
        return (:ecc in ti.tags) && (:ecc_syndrome_measurement_correctness in ti.tags) && all(!in(exclude), ti.tags)

    elseif get(ENV, "ECC_TEST", "") == "bespoke"
        return (:ecc in ti.tags) && (:ecc_bespoke_checks in ti.tags) && all(!in(exclude), ti.tags)
    else
        push!(exclude, :ecc)
    end

    if CUDA_flag
        return (:cuda in ti.tags) && all(!in(exclude), ti.tags)
    else
        push!(exclude, :cuda)
    end

    if ROCm_flag
        return (:rocm in ti.tags) && all(!in(exclude), ti.tags)
    else
        push!(exclude, :rocm)
    end

    if OpenCL_flag
        return (:opencl in ti.tags) && all(!in(exclude), ti.tags)
    else
        push!(exclude, :opencl)
    end

    if !(VERSION >= v"1.10")
        push!(exclude, :doctests)
        push!(exclude, :aqua)
    end

    if !(Base.Sys.islinux() & (Int===Int64))
        push!(exclude, :bitpack)
    end

    return all(!in(exclude), ti.tags)
end

println("Starting tests with $(Threads.nthreads()) threads out of `Sys.CPU_THREADS = $(Sys.CPU_THREADS)`...")

@run_package_tests filter=testfilter
