#pragma once
#ifndef MEDIUM_H__
#define MEDIUM_H__

#include <core/fwd.h>
#include "tetra.hpp"
#include <core/object.h>

struct Ray;
struct RndSampler;
struct Medium;

static constexpr int max_null_interactions = 100;

struct MediumSamplingRecord
{
    Float t;
    Vector p;
    Vector wi;
    Float pdfSuccess; // the probability density of sampling the medium interaction
    Float pdfFailure; // the probability of not sampling any medium interactions
    Spectrum sigmaS;
    Float sigmaT;
    const Medium *medium;
    Float transmittance;
};

struct Medium : Object
{
    Medium(int phase_id) : phase_id(phase_id) {}

    virtual ~Medium() {}
    virtual Medium *clone() const = 0;
    virtual void merge(Medium *emitter) = 0;
    virtual void setZero() = 0;

    void setTetmesh(const std::vector<Vector> &vertices,
                    const std::vector<Vector3i> &indices,
                    const std::vector<std::pair<int, int>> &ids)
    {
        assert(vertices.size() == ids.size());
        m_tetmesh = TetrahedronMesh(vertices, indices, ids);
    }

    Vector4i getTet(int i) const
    {
        return m_tetmesh.getTet(i);
    }

    Vector getVertex(const Scene &scene, int i) const
    {
        return m_tetmesh.getVertex(scene, i);
    }

    virtual bool sampleDistance(const Ray &ray, const Float &tmax,
                                const Array2 &rnd2, RndSampler *sampler,
                                Vector &p_scatter,
                                Spectrum &throughput) const = 0;

    virtual bool sampleDistance(const Ray &ray, const Float &tmax,
                                RndSampler *sampler,
                                MediumSamplingRecord &mRec) const = 0;

    Float evalTransmittance(const Ray &ray, const Float &tmin,
                            const Float &tmax,
                            RndSampler *sampler) const;

    virtual bool isHomogeneous() const = 0;

    Spectrum sigS(const Vector &x) const;
    Float sigT(const Vector &x) const;

    int phase_id;

    // rotation and translation.
    Matrix3x3 m_volumeToWorld_R;
    Vector m_volumeToWorld_T;
    TetrahedronMesh m_tetmesh;

    PSDR_DECLARE_VIRTUAL_CLASS()
};

#endif // MEDIUM_H__
