using SciMLTesting, StochasticDiffEqCore, Test
using JET
import OrdinaryDiffEqCore

# StochasticDiffEqCore extends OrdinaryDiffEqCore's solver loop and dispatches on
# a handful of still-internal SciMLBase/DiffEqBase interface names. The base
# packages (OrdinaryDiffEqCore/DiffEqBase) now declare their solver-author API
# public, so every name that became public was dropped from the ignore lists
# below. Each remaining ignore is a genuinely non-public (or non-owner) name
# from an upstream package, documented with its source. See
# SciML/OrdinaryDiffEq.jl#3776.

# OrdinaryDiffEqCore names this package dispatches on/extends that were kept
# owner-internal (loop/trait/autodiff/noise helpers not in the public
# solver-author surface). These need make-public upstream before they can drop.
const ODEC_INTERNAL = (
    :_determine_initdt, :_get_fdtype, :_get_fwd_chunksize, :_get_fwd_chunksize_int,
    :_initialize_dae!, :_ode_init, :accept_noise!, :concrete_jac, :get_chunksize,
    :handle_callback_modifiers!, :has_autodiff, :is_noise_saveable, :noise_curt,
    :ode_determine_initdt, :qsteady_max_default, :qsteady_min_default,
    :reinit_noise!, :reject_noise!, :save_noise!, :standardtag,
)

# Still-internal SciMLBase interface names (pending SciMLBase#1412 round-5
# make-public; not yet public on the registered SciMLBase this branch resolves).
const SCIMLBASE_INTERNAL = (
    :__has_mass_matrix, :_unwrap_val, :has_initializeprob, :parameterless_type,
)

# `@..` is owned by FastBroadcast and reaches StochasticDiffEqCore through
# DiffEqBase's re-export (the standard SciML access path); it is non-public in
# DiffEqBase, so it is ignored for the are-public check as well as via-owners.
const DIFFEQBASE_INTERNAL = (Symbol("@.."),)

# Non-public names from other upstream packages.
const JUMPPROCESSES_INTERNAL = (:reset_jump_problem!, :resetted_jump_problem)
const DIFFEQNOISEPROCESS_INTERNAL = (:resize_stack!,)
const FORWARDDIFF_INTERNAL = (:Tag, :pickchunksize)
const BASE_INTERNAL = (Symbol("@pure"),)

const NONPUBLIC_IGNORE = (
    ODEC_INTERNAL..., SCIMLBASE_INTERNAL..., DIFFEQBASE_INTERNAL...,
    JUMPPROCESSES_INTERNAL..., DIFFEQNOISEPROCESS_INTERNAL...,
    FORWARDDIFF_INTERNAL..., BASE_INTERNAL...,
)

const ODEC_STOCHASTIC_SURFACE = (
    OrdinaryDiffEqCore.ODEIntegrator,
    OrdinaryDiffEqCore.CompositeCache,
    OrdinaryDiffEqCore.StochasticDiffEqAlgorithm,
    OrdinaryDiffEqCore.StochasticDiffEqAdaptiveAlgorithm,
    OrdinaryDiffEqCore.StochasticDiffEqCompositeAlgorithm,
    OrdinaryDiffEqCore.StochasticDiffEqRODEAlgorithm,
    OrdinaryDiffEqCore.StochasticDiffEqRODEAdaptiveAlgorithm,
    OrdinaryDiffEqCore.StochasticDiffEqRODECompositeAlgorithm,
    OrdinaryDiffEqCore.StochasticDiffEqNewtonAdaptiveAlgorithm,
    OrdinaryDiffEqCore.StochasticDiffEqNewtonAlgorithm,
    OrdinaryDiffEqCore.StochasticDiffEqJumpAlgorithm,
    OrdinaryDiffEqCore.StochasticDiffEqJumpAdaptiveAlgorithm,
    OrdinaryDiffEqCore.StochasticDiffEqJumpNewtonAdaptiveAlgorithm,
    OrdinaryDiffEqCore.StochasticDiffEqJumpDiffusionAlgorithm,
    OrdinaryDiffEqCore.StochasticDiffEqJumpDiffusionAdaptiveAlgorithm,
    OrdinaryDiffEqCore.StochasticDiffEqJumpNewtonDiffusionAdaptiveAlgorithm,
    OrdinaryDiffEqCore.StochasticDiffEqCache,
    OrdinaryDiffEqCore.StochasticDiffEqConstantCache,
    OrdinaryDiffEqCore.StochasticDiffEqMutableCache,
    OrdinaryDiffEqCore._initialize_dae!,
    OrdinaryDiffEqCore.accept_noise!,
    OrdinaryDiffEqCore.is_noise_saveable,
    OrdinaryDiffEqCore.noise_curt,
    OrdinaryDiffEqCore.reinit_noise!,
    OrdinaryDiffEqCore.reject_noise!,
    OrdinaryDiffEqCore.save_noise!,
)

# Solver-author API owned and declared `public` by OrdinaryDiffEqCore (all documented in
# docs/src/devtools/internals/public_api.md) that StochasticDiffEqCore re-exports so the
# StochasticDiffEq solver sublibraries get the SDE extension surface from one package.
const ODEC_PUBLIC_REEXPORTS = (
    :StochasticDiffEqAlgorithm, :StochasticDiffEqAdaptiveAlgorithm,
    :StochasticDiffEqCompositeAlgorithm,
    :StochasticDiffEqRODEAlgorithm, :StochasticDiffEqRODEAdaptiveAlgorithm,
    :StochasticDiffEqRODECompositeAlgorithm,
    :StochasticDiffEqNewtonAlgorithm, :StochasticDiffEqNewtonAdaptiveAlgorithm,
    :StochasticDiffEqJumpAlgorithm, :StochasticDiffEqJumpAdaptiveAlgorithm,
    :StochasticDiffEqJumpNewtonAdaptiveAlgorithm,
    :StochasticDiffEqJumpDiffusionAlgorithm, :StochasticDiffEqJumpDiffusionAdaptiveAlgorithm,
    :StochasticDiffEqJumpNewtonDiffusionAdaptiveAlgorithm,
    :StochasticDiffEqCache, :StochasticDiffEqConstantCache, :StochasticDiffEqMutableCache,
    :issplit,
)

# `SDEIntegrator` and `SDEOptions` are StochasticDiffEqCore's own public API, but they are
# `const` aliases of OrdinaryDiffEqCore types (`ODEIntegrator{<:SDEAlgTypes}` and
# `DEOptions`), and `public_reexports` attributes an alias to the aliased type's module.
const SDEC_TYPE_ALIASES = (:SDEIntegrator, :SDEOptions)

run_qa(
    StochasticDiffEqCore;
    # No docs/ tree here; the umbrella manual renders this package's API.
    api_docs_kwargs = (; rendered = false),
    # `@reexport using DiffEqBase` pulls in DiffEqBase's own API plus its SciMLBase
    # re-export. `names(DiffEqBase)` only propagates SciMLBase's *exports*, so SciMLBase's
    # `public`-but-unexported API (`alg_order`, `isadaptive`) needs its own union entry.
    reexports_allow = union(
        public_api_names(DiffEqBase), public_api_names(SciMLBase),
        (:DiffEqBase,), ODEC_PUBLIC_REEXPORTS, SDEC_TYPE_ALIASES,
    ),
    aqua_kwargs = (; piracies = (; treat_as_own = ODEC_STOCHASTIC_SURFACE)),
    jet_kwargs = (; target_defined_modules = true),
    explicit_imports = true,
    ei_kwargs = (;
        # `@..` reaches StochasticDiffEqCore via DiffEqBase's re-export of
        # FastBroadcast; FastBroadcast is not a direct dependency.
        all_explicit_imports_via_owners = (; ignore = (Symbol("@.."),)),
        all_qualified_accesses_are_public = (; ignore = NONPUBLIC_IGNORE),
        all_explicit_imports_are_public = (; ignore = NONPUBLIC_IGNORE),
    ),
)
