# ===== factorize! with DenseFactorizationWorkspace (bridge to existing methods) =====

function factorize!(
        ::DenseFactorizationWorkspace,
        L::AbstractTriangular{T},
        d::AbstractVector,
        pivot::NoPivot;
        signs::AbstractVector,
        reg::AbstractRegularization,
        check::Bool,
        tol::Real,
    ) where {T}
    return factorize!(L, d, pivot; signs, reg, check, tol)
end

function factorize!(
        ::DenseFactorizationWorkspace,
        L::AbstractTriangular{T},
        d::AbstractVector,
        pivot::RowMaximum,
        perm::AbstractVector,
        invp::AbstractVector;
        signs::AbstractVector,
        reg::AbstractRegularization,
        check::Bool,
        tol::Real,
    ) where {T}
    return factorize!(L, d, pivot, perm, invp; signs, reg, check, tol)
end

# ===== factorize! Level 2: Dense triangular with kwargs =====

function factorize!(
        L::AbstractTriangular{T},
        d::AbstractVector,
        pivot::NoPivot;
        signs::AbstractVector,
        reg::AbstractRegularization,
        check::Bool,
        tol::Real,
    ) where {T}
    @assert checksigns(signs, reg)

    info = factorize!(L, d, pivot, signs, reg, tol)

    if ispositive(info) && check
        if L isa LowerTriangular || L isa UpperTriangular
            throw(PosDefException(info))
        else
            throw(ZeroPivotException(info))
        end
    end

    return info
end

function factorize!(
        L::AbstractTriangular{T},
        d::AbstractVector,
        pivot::RowMaximum,
        perm::AbstractVector,
        invp::AbstractVector;
        signs::AbstractVector,
        reg::AbstractRegularization,
        check::Bool,
        tol::Real,
    ) where {T}
    @assert checksigns(signs, reg)

    info = factorize!(L, d, pivot, perm, invp, signs, reg, tol)

    if ispositive(info) && check
        throw(RankDeficientException(info))
    end

    return info
end

# ===== factorize! Level 3: Dense triangular all positional =====

function factorize!(
        L::AbstractTriangular{T},
        d::AbstractVector,
        pivot::NoPivot,
        signs::AbstractVector,
        reg::AbstractRegularization,
        tol::Real,
    ) where {T}
    S = permuteto(T, signs, eachindex(signs))
    R = initialize(L, S, reg)
    M = parent(L)

    if L isa LowerTriangular || L isa UnitLowerTriangular
        uplo = Val(:L)
    else
        uplo = Val(:U)
    end

    if L isa LowerTriangular || L isa UpperTriangular
        diag = Val(:N)
    else
        diag = Val(:U)
    end

    if diag === Val(:N)
        W = Ones{T}(length(L))
    else
        W = FVector{T}(undef, length(L))
    end

    if R isa SE99
        if diag === Val(:N)
            e = LinearAlgebra.diag(M)
        else
            e = d
            e .= view(M, diagind(M))
        end
    else
        e = d
    end

    return potrf!(uplo, W, M, e, S, R, diag)
end

function factorize!(
        L::AbstractTriangular{T},
        d::AbstractVector,
        pivot::RowMaximum,
        perm::AbstractVector,
        invp::AbstractVector,
        signs::AbstractVector,
        reg::AbstractRegularization,
        tol::Real,
    ) where {T}
    S = permuteto(T, signs, eachindex(signs))
    R = initialize(L, S, reg)
    M = parent(L)

    if L isa LowerTriangular || L isa UnitLowerTriangular
        uplo = Val(:L)
    else
        uplo = Val(:U)
    end

    if L isa LowerTriangular || L isa UpperTriangular
        diag = Val(:N)
    else
        diag = Val(:U)
    end

    W = FVector{T}(undef, length(L))

    if R isa SE99 || R isa GMW81
        if diag === Val(:N)
            e = LinearAlgebra.diag(M)
        else
            e = d .= view(M, diagind(M))
        end
    else
        e = d
    end

    info, rank = pstrf!(uplo, W, M, e, invp, S, R, tol, diag)

    zerotri!(M, rank + 1:size(M, 1), uplo)

    for i in eachindex(perm)
        perm[i] = invp[perm[i]]
    end

    for i in eachindex(perm)
        invp[perm[i]] = i
    end

    return info
end

# ===== DenseDivisionWorkspace bridging methods =====

function LinearAlgebra.ldiv!(::DenseDivisionWorkspace, A::AbstractTriangular, B::AbstractVecOrMat)
    return ldiv!(A, B)
end

function LinearAlgebra.ldiv!(::DenseDivisionWorkspace, A::AdjOrTrans{<:Any, <:AbstractTriangular}, B::AbstractVecOrMat)
    return ldiv!(A, B)
end

function LinearAlgebra.rdiv!(::DenseDivisionWorkspace, B::AbstractMatrix, A::AbstractTriangular)
    return rdiv!(B, A)
end

function LinearAlgebra.rdiv!(::DenseDivisionWorkspace, B::AbstractMatrix, A::AdjOrTrans{<:Any, <:AbstractTriangular})
    return rdiv!(B, A)
end
