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

use crate::common::macros::{integrity_assert_eq, integrity_println};
use crate::corner_table::CornerIndex;
use crate::isotropic_remesh::IsotropicRemeshAlgo;
use std::fmt::Debug;
use vector_traits::num_traits::AsPrimitive;

impl<S, V, const ENABLE_UNSAFE: bool> IsotropicRemeshAlgo<S, V, ENABLE_UNSAFE>
where
    S: crate::common::sealed::ScalarType,
    f64: AsPrimitive<S>,
    V: Debug + Copy + From<[S; 3]> + Into<[S; 3]> + Sync + 'static,
{
    /// Perform the actual edge flip
    /// ```text
    ///              c₀o
    ///      V₃ ─────────────── V₂        V₃ ─────────────── V₂
    ///      │c₀p         c₀n / │         │ \ c₁n        c₁  │
    ///      │              /   │         │   \              │
    ///      │     t₀     / c₁  │         │ c₀p\     t₁      │
    ///      │          /       │     =>  │      \           │
    /// c₀no │        /         │ c₁no    │        \         │
    ///      │      /           │         │          \       │
    ///      │c₀  /      t₁     │         │    t₀      \ c₁p │
    ///      │  /               │         │              \   │
    ///      │/ c₁n         c₁p │         │ c₀         c₀n \ │
    ///      V₀ ────────────── V₁         V₀ ────────────── V₁
    ///              c₁o
    ///
    /// Input: c₀: The corner index at V₀ in the V₀V₂V₃ triangle.
    /// V(c₀)==V₀, V(c₀.prev())==V₃, V(c₀.next())==V₂
    ///
    /// Triangle modifications:
    /// t₀: V₀V₂V₃ (change to V₀V₁V₃)
    /// t₁: V₂V₀V₁ (change to V₂V₃V₁)
    /// New opposites:
    /// c₀ <-> c₁
    /// c₀p <-> old c₁o
    /// c₁p <-> old c₀o
    /// ```
    pub(crate) fn flip_manifold_edge(&mut self, c0: CornerIndex) {
        let (c0n, c0p) = self.corner_table.next_prev(c0); // corners at V₃&V₂ in t₀

        let c1p = self.corner_table.opposite(c0p); // corner at V₁ in t₁
        let (c1, c1n) = self.corner_table.next_prev(c1p); // V₂ & V₃ in t₁

        integrity_assert_eq!(
            self.corner_table.vertex(c1),  // V₂
            self.corner_table.vertex(c0n), // V₂
        );
        integrity_assert_eq!(
            self.corner_table.vertex(c0),  // V₀
            self.corner_table.vertex(c1n)  // V₀
        );
        integrity_assert_eq!(self.corner_table.swing_ccw(c0n), c1);
        integrity_assert_eq!(self.corner_table.swing_cw(c0), c1n);
        integrity_assert_eq!(self.corner_table.twin(c0), c1);
        integrity_assert_eq!(self.corner_table.twin(c1), c0);

        // Get the vertices
        let v0 = self.corner_table.vertex(c0);
        let v1 = self.corner_table.vertex(c1p);
        let v2 = self.corner_table.vertex(c1);
        let v3 = self.corner_table.vertex(c0p);

        #[cfg(feature = "integrity_check")]
        {
            use crate::common::macros::integrity_assert_ne;
            self.corner_table.assert_triangle_vertices_distinct(c0);
            self.corner_table.assert_triangle_vertices_distinct(c1);

            integrity_assert_ne!(v0, v1);
            integrity_assert_ne!(v0, v2);
            integrity_assert_ne!(v0, v3);
            integrity_assert_ne!(v1, v2);
            integrity_assert_ne!(v1, v3);
            integrity_assert_ne!(v2, v3);
        }

        // Store the opposite corners as they were *before* the flip
        let c0_o = self.corner_table.opposite(c0); // opposite across V₂V₃ edge
        #[cfg(feature = "integrity_check")]
        let c0n_o = self.corner_table.opposite(c0n); // opposite across V₃V₀ edge
        let c1_o = self.corner_table.opposite(c1); // opposite across V₁V₀ edge
        #[cfg(feature = "integrity_check")]
        let c1n_o = self.corner_table.opposite(c1n); // opposite across V₀V₁ edge

        integrity_println!("Before flip:");
        integrity_println!("v0:{v0:?}, v1:{v1:?}, v2:{v2:?}, v3:{v3:?}");
        integrity_println!("c0:{}", self.corner_table.data.dbg_corner(c0));
        integrity_println!("c0n:{}", self.corner_table.data.dbg_corner(c0n));
        integrity_println!("c0p:{}", self.corner_table.data.dbg_corner(c0p));
        integrity_println!("c1:{}", self.corner_table.data.dbg_corner(c1));
        integrity_println!("c1n:{}", self.corner_table.data.dbg_corner(c1n));
        integrity_println!("c1p:{}", self.corner_table.data.dbg_corner(c1p));

        integrity_println!("c0_o:{}", self.corner_table.data.dbg_corner(c0_o));
        integrity_println!("c0n_o:{}", self.corner_table.data.dbg_corner(c0n_o));
        integrity_println!("c1_o:{}", self.corner_table.data.dbg_corner(c1_o));
        integrity_println!("c1n_o:{}", self.corner_table.data.dbg_corner(c1n_o));

        // Repurpose t₀: change from V₀V₂V₃ to V₀V₁V₃
        // Currently t₀ is: c₀(V₀), c₀n(V₂), c₀p(V₃)
        // We want:         c₀(V₀), c₀n(V₁), c₀p(V₃)
        self.corner_table.link_corner_vertex(c0n, v1);

        // Repurpose t₁: change from V₂V₀V₁ to V₂V₃V₁
        // Currently t₁ is: c₁(V₂), c₁n(V₀), c₁p(V₁)
        // We want:         c₁(V₂), c₁n(V₃), c₁p(V₁)
        self.corner_table.link_corner_vertex(c1n, v3);

        // Update opposites for the new edge configuration
        // The new diagonal is V₃V₁ connecting the two triangles
        self.corner_table.set_dual_opposite(c1, c0);
        self.corner_table.set_dual_opposite(c0p, c1_o);
        self.corner_table.set_dual_opposite(c1p, c0_o);
        #[cfg(feature = "integrity_check")]
        {
            self.corner_table.assert_dual_opposite(c0n, c0n_o);
            self.corner_table.assert_dual_opposite(c1n, c1n_o);
        }

        // Update default corners for vertices
        self.corner_table.data.set_default_corner_of_vertex(v0, c0);
        self.corner_table.data.set_default_corner_of_vertex(v1, c0n);
        self.corner_table.data.set_default_corner_of_vertex(v2, c1);
        self.corner_table.data.set_default_corner_of_vertex(v3, c1n);

        integrity_assert_eq!(
            self.corner_table.vertex(c0p),
            self.corner_table.vertex(c1n),
            "V(c0p) != V(c1n): v0:{v0:?},v1:{v1:?},v2:{v2:?},v3:{v3:?}, c0 triangle:{} c1 triangle:{}",
            self.corner_table.dbg_triangle(c0),
            self.corner_table.dbg_triangle(c1)
        );
        integrity_assert_eq!(
            self.corner_table.vertex(c0n),
            self.corner_table.vertex(c1p),
            "V(c0n) != V(c1p): v0:{v0:?},v1:{v1:?},v2:{v2:?},v3:{v3:?}, c0 triangle:{} c1 triangle:{}",
            self.corner_table.dbg_triangle(c0),
            self.corner_table.dbg_triangle(c1)
        );

        integrity_assert_eq!(self.corner_table.vertex(c0), v0);
        integrity_assert_eq!(self.corner_table.vertex(c0n), v1);
        integrity_assert_eq!(self.corner_table.vertex(c0p), v3);
        integrity_assert_eq!(self.corner_table.vertex(c1), v2);
        integrity_assert_eq!(self.corner_table.vertex(c1n), v3);
        integrity_assert_eq!(self.corner_table.vertex(c1p), v1);

        integrity_println!("After flip:");
        integrity_println!("v0:{v0:?}, v1:{v1:?}, v2:{v2:?}, v3:{v3:?}");
        integrity_println!("c0:{}", self.corner_table.data.dbg_corner(c0));
        integrity_println!("c0n:{}", self.corner_table.data.dbg_corner(c0n));
        integrity_println!("c0p:{}", self.corner_table.data.dbg_corner(c0p));
        integrity_println!("c1:{}", self.corner_table.data.dbg_corner(c1));
        integrity_println!("c1n:{}", self.corner_table.data.dbg_corner(c1n));
        integrity_println!("c1p:{}", self.corner_table.data.dbg_corner(c1p));

        #[cfg(feature = "integrity_check")]
        {
            self.corner_table.assert_corner_fan_vertices(c0);
            self.corner_table.assert_corner_fan_vertices(c0p);
            self.corner_table.assert_corner_fan_vertices(c0n);
            self.corner_table.assert_corner_fan_vertices(c1p);

            self.corner_table.assert_triangle_vertices_distinct(c0);
            self.corner_table.assert_triangle_vertices_distinct(c1);
        }
    }
}
