#pragma once
#ifndef SPHERE_H__
#define SPHERE_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 Circle {
    Circle() { status = 0; }

    Circle(const Vector& C1, const Vector& C2, const Vector& C3, const Vector& circle_O,
        Float circle_r, Float _tau)
        : orig(circle_O), radius(circle_r), tau(_tau) {
        init(C1, C2, C3);
    }

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

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

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

    // utils
    Float pointToAngle(const Vector &p) const;
    Vector angleToPoint(const Float &angle) const;

    Vector worldToCircle(const Vector &p_world) const;
    Vector circleToWorld(const Vector &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;

    Vector orig;
    Frame circle_frame;
    Float radius;
    Float tau; // radius of the sphere

    std::vector<Vector2> curves;
};

struct Sphere {
    Sphere(const Vector& _orig, const Vector& _n, Float _tau)
        : orig(_orig), n(_n), radius(_tau) {
        init();
    }

    void init();

    Circle intersectTri(const Vector &C1, const Vector &C2, const Vector &C3);

    Vector orig, n;
    Float radius;

    AABB bounds;
};

#endif
