
"""
    RieszRepresenterCotangentVector(M::AbstractManifold, p, X)

Cotangent vector in Riesz representer form on manifold `M` at point `p` with Riesz
representer `X`.
"""
struct RieszRepresenterCotangentVector{TM<:AbstractManifold,TP,TX}
    manifold::TM
    p::TP
    X::TX
end

function allocate(ξ::RieszRepresenterCotangentVector)
    return RieszRepresenterCotangentVector(ξ.manifold, copy(ξ.p), allocate(ξ.X))
end

function (ξ::RieszRepresenterCotangentVector)(Y)
    return inner(ξ.manifold, ξ.p, ξ.X, Y)
end

@decorator_transparent_signature flat!(
    M::AbstractDecoratorManifold,
    ξ::CoTFVector,
    p,
    X::TFVector,
)

@doc raw"""
    flat(M::AbstractManifold, p, X)

Compute the flat isomorphism (one of the musical isomorphisms) of tangent vector `X`
from the vector space of type `M` at point `p` from the underlying [`AbstractManifold`](@ref).

The function can be used for example to transform vectors
from the tangent bundle to vectors from the cotangent bundle
$♭ : T\mathcal M → T^{*}\mathcal M$
"""
flat(M::AbstractManifold, p, X) = RieszRepresenterCotangentVector(M, p, X)
function flat(M::AbstractManifold, p, X::TFVector{<:Any,<:AbstractBasis})
    return CoTFVector(X.data, dual_basis(M, p, X.basis))
end

function flat!(::AbstractManifold, ξ::RieszRepresenterCotangentVector, p, X)
    # TODO: maybe assert that ξ.p is equal to p? Allowing for varying p in ξ leads to
    # issues with power manifold.
    copyto!(ξ.X, X)
    return ξ
end

function get_coordinates(
    M::AbstractManifold,
    p,
    ξ::RieszRepresenterCotangentVector,
    ::DefaultOrthonormalBasis{𝔽,CotangentSpaceType},
) where {𝔽}
    return get_coordinates(M, p, ξ.X, DefaultOrthonormalBasis{𝔽}())
end

function get_coordinates!(
    M::AbstractManifold,
    v,
    p,
    ξ::RieszRepresenterCotangentVector,
    ::DefaultOrthonormalBasis{𝔽,CotangentSpaceType},
) where {𝔽}
    get_coordinates!(M, v, p, ξ.X, DefaultOrthonormalBasis{𝔽}())
    return v
end

function get_vector(
    M::AbstractManifold,
    p,
    v,
    ::DefaultOrthonormalBasis{𝔽,CotangentSpaceType},
) where {𝔽}
    X = get_vector(M, p, v, DefaultOrthonormalBasis{𝔽}())
    return RieszRepresenterCotangentVector(M, p, X)
end

function get_vector!(
    M::AbstractManifold,
    ξr::RieszRepresenterCotangentVector,
    p,
    v,
    ::DefaultOrthonormalBasis{𝔽,CotangentSpaceType},
) where {𝔽}
    get_vector!(M, ξr.X, p, v, DefaultOrthonormalBasis{𝔽}())
    return ξr
end

@doc raw"""
    sharp(M::AbstractManifold, p, ξ)

Compute the sharp isomorphism (one of the musical isomorphisms) of vector `ξ`
from the vector space `M` at point `p` from the underlying [`AbstractManifold`](@ref).

The function can be used for example to transform vectors
from the cotangent bundle to vectors from the tangent bundle
$♯ : T^{*}\mathcal M → T\mathcal M$
"""
sharp(::AbstractManifold, p, ξ)

sharp(::AbstractManifold, p, ξ::RieszRepresenterCotangentVector) = ξ.X
function sharp(M::AbstractManifold, p, X::CoTFVector{<:Any,<:AbstractBasis})
    return TFVector(X.data, dual_basis(M, p, X.basis))
end

@decorator_transparent_signature sharp!(
    M::AbstractDecoratorManifold,
    X::TFVector,
    p,
    ξ::CoTFVector,
)

function sharp!(::AbstractManifold, X, p, ξ::RieszRepresenterCotangentVector)
    copyto!(X, ξ.X)
    return X
end
