// SPDX-License-Identifier: MIT OR Apache-2.0
// Copyright (c) 2025 lacklustr@protonmail.com https://github.com/eadf

use crate::common::VertexIndex;
use crate::common::macros::{integrity_assert, integrity_assert_eq};
use crate::corner_table::CornerIndex;
use crate::corner_table::triangle_index::TriangleIndex;
use crate::util::index_pool::LifoPool;
use smallvec::SmallVec;

pub(crate) const DEFAULT_MAX_VALENCE: i16 = 8;

#[derive(Clone)]
pub(crate) struct CornerTableData<const ENABLE_UNSAFE: bool> {
    /// For each corner, the vertex it points to
    pub(super) vertex_of_corner_vec: Vec<VertexIndex>,
    /// For each corner, the opposite corner (across the edge)
    pub(super) opposite_corner_vec: Vec<CornerIndex>,
    /// For each vertex, one corner that points to it (arbitrary choice)
    pub(super) corner_of_vertex_vec: Vec<CornerIndex>,
}

/// Corner table data structure for efficient mesh traversal
#[derive(Clone)]
pub(crate) struct CornerTable<const ENABLE_UNSAFE: bool> {
    /// keeps track of the corner table
    pub(crate) data: CornerTableData<ENABLE_UNSAFE>,
    /// keeps track of deleted triangles
    pub(crate) triangle_pool: LifoPool<TriangleIndex, ENABLE_UNSAFE>,
}

pub(crate) type VertexFan = SmallVec<[CornerIndex; 7]>;

impl<const ENABLE_UNSAFE: bool> CornerTable<ENABLE_UNSAFE> {
    pub(crate) fn new(
        vertex_of_corner: Vec<VertexIndex>,
        opposite_corner: Vec<CornerIndex>,
        corner_of_vertex: Vec<CornerIndex>,
    ) -> Self {
        let num_corners = vertex_of_corner.len() as u32;
        debug_assert_eq!(num_corners, opposite_corner.len() as u32);
        let triangle_pool = LifoPool::<TriangleIndex, ENABLE_UNSAFE>::new(num_corners / 3);
        debug_assert_eq!(num_corners / 3, triangle_pool.total_count());

        Self {
            data: CornerTableData {
                vertex_of_corner_vec: vertex_of_corner,
                opposite_corner_vec: opposite_corner,
                corner_of_vertex_vec: corner_of_vertex,
            },
            triangle_pool,
        }
    }

    #[inline(always)]
    pub(crate) fn vertex_of_corners(&self) -> &[VertexIndex] {
        &self.data.vertex_of_corner_vec
    }

    /// returns a canonical (VertexIndex, VertexIndex) edge representation
    #[inline(always)]
    pub(crate) fn canonical_edge(&self, corner: CornerIndex) -> (VertexIndex, VertexIndex) {
        let vc = self.vertex(corner);
        let vc_next = self.vertex(self.next(corner));
        VertexIndex::canonical_pair(vc, vc_next)
    }

    /// returns a canonical edge representation
    #[inline(always)]
    pub(crate) fn canonical_edge_hash(&self, corner: CornerIndex) -> u64 {
        use std::hash::{DefaultHasher, Hash, Hasher};
        let mut hasher = DefaultHasher::new();
        self.canonical_edge(corner).hash(&mut hasher);
        hasher.finish()
    }

    #[inline(always)]
    pub fn is_triangle_deleted(&self, t: TriangleIndex) -> bool {
        !t.is_valid()
            || if cfg!(any(feature = "integrity_check", debug_assertions)) {
                assert!(t.0 < self.triangle_pool.total_count());
                let fast_method =
                    !self.data.vertex_of_corner_vec[t.base_corner().0 as usize].is_valid();
                let slow_method = !self.triangle_pool.is_used(t);
                assert_eq!(fast_method, slow_method);
                fast_method
            } else {
                !if ENABLE_UNSAFE {
                    unsafe {
                        *self
                            .data
                            .vertex_of_corner_vec
                            .get_unchecked(t.base_corner().0 as usize)
                    }
                } else {
                    self.data.vertex_of_corner_vec[t.base_corner().0 as usize]
                }
                .is_valid()
            }
    }

    /// returns true if the triangle of the corner is deleted
    #[inline(always)]
    pub fn is_corner_deleted(&self, c: CornerIndex) -> bool {
        !c.is_valid()
            || if cfg!(any(feature = "integrity_check", debug_assertions)) {
                let fast_method = !self.data.vertex_of_corner_vec[c.0 as usize].is_valid();
                let slow_method = !self.triangle_pool.is_used(c.triangle());
                assert_eq!(fast_method, slow_method);
                fast_method
            } else {
                !if ENABLE_UNSAFE {
                    unsafe { *self.data.vertex_of_corner_vec.get_unchecked(c.0 as usize) }
                } else {
                    self.data.vertex_of_corner_vec[c.0 as usize]
                }
                .is_valid()
            }
    }

    #[inline(always)]
    pub(crate) fn deleted_triangle_count(&self) -> u32 {
        self.triangle_pool.available_count()
    }

    /// returns the number of triangles (active and in the pool)
    #[inline(always)]
    pub(crate) fn total_triangle_count(&self) -> u32 {
        integrity_assert_eq!(
            self.data.vertex_of_corner_vec.len(),
            self.data.opposite_corner_vec.len()
        );
        integrity_assert_eq!(
            self.triangle_pool.total_count(),
            self.data.vertex_of_corner_vec.len() as u32 / 3
        );

        self.triangle_pool.total_count()
    }

    #[inline(always)]
    /// returns the number of active triangles
    pub(crate) fn active_triangles(&self) -> u32 {
        self.triangle_pool.active_count()
    }

    /// Take triangles as Vec<u32> in O(1)
    pub(crate) fn take_triangles(self) -> Vec<u32> {
        bytemuck::cast_vec::<VertexIndex, u32>(self.data.vertex_of_corner_vec)
    }

    /// Clone a vertex and set up the pointers
    pub(super) fn clone_vertex<T: Clone>(
        &mut self,
        vertices: &mut Vec<T>,
        source_vertex: VertexIndex,
    ) -> VertexIndex {
        integrity_assert_eq!(vertices.len(), self.data.corner_of_vertex_vec.len());
        let new_vertex_idx = VertexIndex(vertices.len() as u32);
        vertices.push(vertices[source_vertex.usize()].clone());
        self.data.corner_of_vertex_vec.push(CornerIndex::INVALID);

        integrity_assert_eq!(vertices.len(), self.data.corner_of_vertex_vec.len());
        new_vertex_idx
    }

    pub(crate) fn dbg_corner(&self, c: CornerIndex) -> String {
        self.data.dbg_corner(c)
    }

    pub(crate) fn dbg_corners(&self, corners: &[CornerIndex]) -> String {
        corners
            .iter()
            .map(|c| self.dbg_corner(*c))
            .collect::<Vec<_>>()
            .join(",")
    }
}

impl<const ENABLE_UNSAFE: bool> CornerTableData<ENABLE_UNSAFE> {
    #[inline(always)]
    pub(crate) fn set_default_corner_of_vertex(
        &mut self,
        vertex: VertexIndex,
        corner: CornerIndex,
    ) {
        integrity_assert!(corner.is_valid());
        integrity_assert!(vertex.is_valid());
        if ENABLE_UNSAFE {
            unsafe {
                *self
                    .corner_of_vertex_vec
                    .get_unchecked_mut(vertex.0 as usize) = corner;
            }
        } else {
            self.corner_of_vertex_vec[vertex.0 as usize] = corner;
        }

        //integrity_println!("set corner of vertex {vertex}->{}", self.corner_table.data.dbg_corner(corner));
    }

    pub(crate) fn dbg_corner(&self, c: CornerIndex) -> String {
        let o = self.opposite(c);
        let o = if o.is_valid() {
            format!("{}", o.0)
        } else {
            "∅".to_string()
        };
        format!("{c:?}O{}{:?}", o, self.vertex_of_corner(c))
    }
}
