#ifndef VIS_ENGINE_MESH_HPP
#define VIS_ENGINE_MESH_HPP

#include "triangle.hpp"
#include "point.hpp"
#include "share.hpp"

#include <unordered_map>
#include <type_traits>
#include <algorithm>
#include <iterator>
#include <vector>

namespace visual_engine {

class mesh final {
    using triangle_          = detail::linalg::triangle_;
    using triangle_container = std::vector<triangle_>;
    using point_container    = std::vector<point>;

    point_container    point_buff;
    triangle_container triag_buff;

public:
    template<typename It>
        // requires std::is_same_v<typename std::iterator_traits<It>::value_type, triangle>
    mesh(It itb, It end, count_t N) {
        std::unordered_map<point, int, point::point_hasher> map;
        int ind = 0;
        for (It tmp = itb; tmp != end; ++tmp) {
            point a = tmp->get_a(),
                  b = tmp->get_b(),
                  c = tmp->get_c();
            if (map.find(a) == map.end())
                map.emplace(a, ind++);
            if (map.find(b) == map.end())
                map.emplace(b, ind++);
            if (map.find(c) == map.end())
                map.emplace(c, ind++);
        }

        using pip = std::pair<int, point>;
        std::vector<pip> tmp_vec;
        for (auto it = map.begin(), ite = map.end(); it != ite; ++it)
            tmp_vec.emplace_back(std::pair{it->second, it->first});
        std::sort(tmp_vec.begin(), tmp_vec.end(), [](pip a, pip b) { return a.first < b.first; });

        point_buff.reserve(ind);
        triag_buff.reserve(N);
        for (auto &&i : tmp_vec) point_buff.push_back(i.second);
        for (; itb != end; ++itb) {
            point a = itb->get_a(),
                  b = itb->get_b(),
                  c = itb->get_c();
            triag_buff.emplace_back(map.find(a)->second, map.find(b)->second,
                                    map.find(c)->second, itb->get_norm());
        }
}

    void console_dump() const;
    void rotate(const point& p, const vector& v);
    void move(const vector& v);
    std::optional<std::pair<coord_t, double>> get_best_line_intersection_mesh(const point &p, const vector &v, coord_t vp_dist) const;
};

} // namespace visual_engine

#endif // VIS_ENGINE_MESH_HPP
