#pragma once
#ifndef SPHERE_AD_H__
#define SPHERE_AD_H__

#include "fwd.h"
#include "frameAD.h"
#include "ptr.h"
#include "utils.h"
#include "aabb.h"
#include <cmath>
#include <string>
#include <vector>
#include <array>
#include <cmath>

struct CircleAD {
    CircleAD() { status = 0; }

    CircleAD(const VectorAD& C1, const VectorAD& C2, const VectorAD& C3, const VectorAD& circle_O,
        const FloatAD& circle_r, const FloatAD& _tau)
        : orig(circle_O), radius(circle_r), tau(_tau) {
        init(C1, C2, C3);
    }

    void init(const VectorAD &C1, const VectorAD &C2, const VectorAD &C3);

    VectorAD sampleCircularCurve(const Float &rn, Float &phi, Float &pdf, FloatAD &jacobian);

    inline bool canSample() { return status == 3; }

    // utils
    FloatAD pointToAngleAD(const VectorAD &p) const;
    VectorAD angleToPointAD(const FloatAD &angle) const;

    VectorAD worldToCircleAD(const VectorAD &p_world) const;
    VectorAD circleToWorldAD(const VectorAD &p_circle) const;

    /*
     * 0 - The ellipsoid doesn't intersect with the plane.
     * 1 - The ellipsoid intersects with the plane but the ellipse doesn't
     * intersect with the triangle.
     * 2 - The ellipse intersects with the triangle but none of elliptic
     * curves lies inside the triangle.
     * 3 - There are elliptic curves lying inside the triangle.
     */
    int status;

    VectorAD orig;
    FrameAD circle_frame;
    FloatAD radius;
    FloatAD tau; // radius of the sphere

    std::vector<Vector2AD> curves;
};

struct SphereAD {
    SphereAD(const VectorAD& _orig, const VectorAD& _n, const FloatAD& _tau)
        : orig(_orig), n(_n), radius(_tau) {
        init();
    }

    void init();

    CircleAD intersectTri(const VectorAD &C1, const VectorAD &C2, const VectorAD &C3);

    VectorAD orig, n;
    FloatAD radius;

    AABB bounds;
};

#endif
