#include <cmath>
#include <iostream>
#include <unordered_map>

#include "mesh.hpp"
#include "point.hpp"
#include "vector.hpp"
#include "matrix.hpp"

using namespace visual_engine;
using triangle = detail::linalg::triangle_;

void mesh::console_dump() const {
    std::cout << "MESH:" << std::endl;
    std::cout << "all points:" << std::endl;
    int idx = 0;
    for (auto &&it = point_buff.begin(), ite = point_buff.end(); it != ite; ++it) {
        std::cout << idx++ << ") ";
        it->console_dump();
    }
    std::cout << "all triangles:" << std::endl;
    for (auto &&it = triag_buff.begin(), ite = triag_buff.end(); it != ite; ++it)
        it->console_dump();
    std::cout << std::endl;
}

using paircd = std::pair<coord_t, double>;

std::optional<paircd> mesh::get_best_line_intersection_mesh(const point &p, const vector &v, coord_t lower_render_dist) const {
    paircd best{0, 0};
    for (triangle_ elem : triag_buff) {
        double cos = v.normalized().scal_product(elem.get_norm());
        if (cos > 0) continue;
        auto t = elem.line_intersect_triag_param(point_buff, p, v);
        if (!t.has_value()) continue;
        coord_t dist = t.value() * v.length();
        if (dist < 0 || dist < lower_render_dist) continue;
        if (best == paircd{0,0} || dist < best.first)
            best = paircd{dist, cos};
    }

    if (best == paircd{0,0}) return std::nullopt;
    return best;
}

void mesh::rotate(const point& p, const vector& v) {
    for (auto &&pt : point_buff) pt.rotate(p, v);
    for (auto &&tr : triag_buff) tr.norm_rotate(v);
}

void mesh::move(const vector& v) {
    for (auto &&i : point_buff) i.move(v);
}

