# Maybe ditch this ideal type for now - still has limited functionality
##############
# MatPolyIdeal interface
##############
#  https://docs.oscar-system.org/stable/AlgebraicGeometry/FrameWorks/ArchitectureOfAffineSchemes/

# MatPolyIdeal definition
struct MatPolyIdeal{T, R<:MatPolyRing} <: Ideal{T}
    R::R
    gens::Vector{T}
    I::MPolyIdeal

    function MatPolyIdeal(R::MatPolyRing, g::Union{RingElem, RingElement, Integer}...)
        T = Oscar.elem_type(R.S)
        oscar_gens = [R.S(R(f)) for f in g]
        I = ideal(R.S, oscar_gens)
        new{T, typeof(R)}(R, [R(f) for f in g], I)
    end

    function MatPolyIdeal(R::MatPolyRing, g::Vector)
        T = Oscar.elem_type(R.S)
        oscar_gens = [R.S(R(f)) for f in g]
        I = ideal(R.S, oscar_gens)
        new{T, typeof(R)}(R, [R(f) for f in g], I)
    end
end


# Quotient ring constructor
function Oscar.quo(R::MatPolyRing, I::MatPolyIdeal)
    Q, f = quo(R.S, I.I)
    return Q, f
end

# Quotient ring constructor
function Oscar.quo(R::MatPolyRing, I::MatPolyIdeal)
    Q, f = quo(R.S, I.I)
    return Q, f
end

# Ideal membership test
function Base.in(f::RingElem, I::MatPolyIdeal)
    return I.R.S(f) in I.I
end

# Generators
Oscar.gens(I::MatPolyIdeal) = I.gens

# Coordinates
function Oscar.coordinates(f::RingElem, I::MatPolyIdeal)
    return Oscar.coordinates(I.R.S(f), I.I)
end

# Show method for MatPolyIdeal
function Base.show(io::IO, I::MatPolyIdeal)
    print(io, "Ideal in ", I.R, " generated by ", I.gens)
end

# Implement necessary methods for Ideal interface
Oscar.base_ring(I::MatPolyIdeal) = I.R
Oscar.ngens(I::MatPolyIdeal) = length(I.gens)
Oscar.gen(I::MatPolyIdeal, i::Int) = I.gens[i]


# Sum of ideals
function Base.:+(I::MatPolyIdeal, J::MatPolyIdeal)
    @assert I.R == J.R "Ideals must be in the same ring"
    K = I.I + J.I  # Using Oscar's implementation
    return MatPolyIdeal(I.R, gens(K))
end

# Product of ideals
function Base.:*(I::MatPolyIdeal, J::MatPolyIdeal)
    @assert I.R == J.R "Ideals must be in the same ring"
    K = I.I * J.I  # Using Oscar's implementation
    return MatPolyIdeal(I.R, gens(K))
end

# Intersection of ideals
function Oscar.intersect(I::MatPolyIdeal, J::MatPolyIdeal)
    @assert I.R == J.R "Ideals must be in the same ring"
    K = intersect(I.I, J.I)  # Using Oscar's implementation
    return MatPolyIdeal(I.R, gens(K))
end

# Quotient of ideals
function Oscar.quotient(I::MatPolyIdeal, J::MatPolyIdeal)
    @assert I.R == J.R "Ideals must be in the same ring"
    K = quotient(I.I, J.I)  # Using Oscar's implementation
    return MatPolyIdeal(I.R, gens(K))
end

# Saturation of an ideal
function Oscar.saturation(I::MatPolyIdeal, J::MatPolyIdeal)
    @assert I.R == J.R "Ideals must be in the same ring"
    K = saturation(I.I, J.I)  # Using Oscar's implementation
    return MatPolyIdeal(I.R, gens(K))
end

# Radical of an ideal
function Oscar.radical(I::MatPolyIdeal)
    K = radical(I.I)  # Using Oscar's implementation
    return MatPolyIdeal(I.R, gens(K))
end

# Primary decomposition of an ideal
function Oscar.primary_decomposition(I::MatPolyIdeal)
    decomp = primary_decomposition(I.I)  # Using Oscar's implementation
    return [MatPolyIdeal(I.R, gens(J)) for J in decomp]
end

# Equality test for ideals
function Base.:(==)(I::MatPolyIdeal, J::MatPolyIdeal)
    return I.R == J.R && I.I == J.I
end

# Subset test for ideals
function Base.issubset(I::MatPolyIdeal, J::MatPolyIdeal)
    @assert I.R == J.R "Ideals must be in the same ring"
    return issubset(I.I, J.I)
end