using Sundials, Test
import ODEProblemLibrary: prob_ode_linear, prob_ode_2Dlinear

prob = prob_ode_linear
dt = 1 // 2^(4)
sol = solve(prob, ARKODE())
@test sol.errors[:l2] < 5.0e-2
sol = solve(prob, ARKODE(); abstol = [1.0e-7])

f1 = (du, u, p, t) -> du .= u
f2 = (du, u, p, t) -> du .= u

prob = prob_ode_2Dlinear
dt = 1 // 2^(4)
# Testing LapackDense solver
sol_lapack = solve(prob, ARKODE(; linear_solver = :LapackDense))
@test sol_lapack.retcode == ReturnCode.Success

prob = SplitODEProblem(
    SplitFunction(f1, f2; analytic = (u0, p, t) -> exp(2t) * u0),
    rand(4, 2),
    (0.0, 1.0)
)

sol = solve(prob, ARKODE(; linear_solver = :Dense))
@test sol.errors[:l2] < 1.0e-2

# Testing LapackBand solver
sol = solve(
    prob,
    ARKODE(; linear_solver = :LapackBand, jac_upper = 3, jac_lower = 3);
    reltol = 1.0e-12,
    abstol = 1.0e-12
)
@test sol.errors[:l2] < 1.0e-6

#
# Test for Sundials.jl issue #253
#
# ARKStepSetERKTableNum not defined
#
# COMMENTED OUT: Causes segfault in SUNDIALS 7.4 - SUNNonlinSolGetType error
# The max_nonlinear_iters parameter seems incompatible with explicit RK methods in 7.4
#
# Function
function Eq_Dif(dq, q, t)
    return dq .= 10 * q
end
# Alias
fn(dq, q, p, t) = Eq_Dif(dq, q, t)
# Time span
tspan = (0.0, 1.0)
# Initial values
q = zeros(10)
# Define problem
prob = ODEProblem(fn, q, tspan)
# Test explicit ARKODE methods with ERKStep
method = ARKODE(
    Sundials.Explicit();
    etable = Sundials.VERNER_8_5_6,
    order = 8,
    set_optimal_params = false,
    max_hnil_warns = 10,
    max_error_test_failures = 7
)
# Removed max_nonlinear_iters and max_convergence_failures as they don't apply to explicit methods
# Solve
sol = solve(prob, method)
@test sol.retcode == ReturnCode.Success

# Simpler explicit ARKODE test
method2 = ARKODE(Sundials.Explicit(); etable = Sundials.VERNER_8_5_6)
sol2 = solve(prob, method2)
@test sol2.retcode == ReturnCode.Success

# Also test default implicit ARKODE method
method = ARKODE()
sol = solve(prob, method)
@test sol.retcode == ReturnCode.Success

#test that save_start and save_end are false by default when saveat is set
sol = solve(prob, ARKODE(), saveat = [0.1, 0.2])
@test sol.t == [0.1, 0.2]
