use glam::vec2;

use super::EPS;
use crate::{
    Aabb,
    math_curve::are_very_close_points,
    math_segment::{Segment, SegmentColor},
    segment::cycle_color,
};

pub(super) enum RecolorVisit {
    Start {
        index: usize,
    },
    Continue {
        index: usize,
        previous_angle: i16,
        previous_color: SegmentColor,
    },
}
pub(super) fn recolor(segments: &mut [Segment], state: &mut super::IntersectRemoveState) {
    state.stack.clear();
    state.stack.push(RecolorVisit::Start { index: 0 });
    state.visited.clear();
    state.visited.resize(segments.len(), false);

    fn push_next_segments(segments: &mut [Segment], i: usize, stack: &mut Vec<RecolorVisit>) {
        let seg = segments[i];
        let mut seg_aabb = Aabb::from_segment(seg);
        seg_aabb.min -= vec2(EPS, EPS);
        seg_aabb.max += vec2(EPS, EPS);

        let mut is_first = true;
        super::visit_bvh(segments, &|aabb| aabb.overlap(&seg_aabb), &mut |i| {
            if are_very_close_points(seg.to, segments[i].from) {
                if is_first {
                    stack.push(RecolorVisit::Continue {
                        index: i,
                        previous_angle: seg.angle(),
                        previous_color: seg.color,
                    });
                    is_first = false;
                } else {
                    stack.push(RecolorVisit::Start { index: i });
                }
            }
        });
    }

    while let Some(visit) = state.stack.pop() {
        match visit {
            RecolorVisit::Start { index } => {
                if state.visited[index] {
                    continue;
                }
                state.visited[index] = true;
                segments[index].color = SegmentColor::BlueRed;
                push_next_segments(segments, index, &mut state.stack);
            }
            RecolorVisit::Continue {
                index,
                previous_angle,
                previous_color,
            } => {
                if state.visited[index] {
                    continue;
                }
                state.visited[index] = true;
                let angle = segments[index].angle();
                let is_corner = if let Some(seg_prev_angle) = segments[index].prev_angle {
                    segments[index].prev_angle = None;
                    seg_prev_angle != previous_angle
                } else {
                    segments[index].prev_angle = Some(previous_angle);
                    angle != previous_angle
                };
                let mut color = previous_color;
                if is_corner {
                    cycle_color(&mut color);
                }
                segments[index].color = color;
                push_next_segments(segments, index, &mut state.stack);
            }
        }
    }
}
