#[derive(Clone, Debug, Default)]
pub struct Path {
    pub segments: Vec<PathSegment>,
    pub original: String,
}

#[derive(Clone, Debug)]
pub enum PathSegment {
    Static(String),
    Dynamic(String),           // [slug]
    CatchAll(String),          // [...slug]
    OptionalCatchAll(String),  // [[...slug]]
}

impl Path {
    /// Creates a structured Path from a string like "/user/[id]/settings"
    pub fn from_str(path: &str) -> Self {
        let trimmed = path.trim().trim_matches('/');
        
        if trimmed.is_empty() {
            return Self {
                segments: vec![PathSegment::Static("".to_string())],
                original: "/".to_string(),
            };
        }

        let segments = trimmed
            .split('/')
            .map(PathSegment::parse_one)
            .collect();

        Self { 
            segments,
            original: format!("/{}", trimmed),
        }
    }

    /// Compiles the entire path for the Matchit router
    /// Example: "/user/[id]" -> "/user/:id"
    pub fn to_matchit_pattern(&self) -> String {
        let mut pattern = String::new();
        for segment in &self.segments {
            let part = segment.to_matchit_single();
            if part.is_empty() && self.segments.len() == 1 {
                return "/".to_string();
            }
            pattern.push('/');
            pattern.push_str(&part);
        }
        pattern
    }

    pub fn split_optional_catch_all(&self) -> Option<(String, String)> {
        if let Some(PathSegment::OptionalCatchAll(_)) = self.segments.last() {
            // Full pattern with catch‑all (e.g., "/user/{*slug}")
            let full_pattern = self.to_matchit_pattern();
            // Build pattern without the last segment
            let base_segments = &self.segments[..self.segments.len() - 1];
            let mut base_path = String::new();
            for seg in base_segments {
                base_path.push('/');
                base_path.push_str(&seg.to_matchit_single());
            }
            if base_path.is_empty() { base_path = "/".to_string(); }
            Some((base_path, full_pattern))
        } else {
            None
        }
    }

    pub fn prepend(&mut self, prefix: &Path) {
        // Guard: If the prefix path is just a root "/", do nothing
        if prefix.segments.len() == 1 && match &prefix.segments[0] { PathSegment::Static(s) => s.is_empty(), _ => false } {
            return;
        }

        // Check if our current path is just a root "/" path
        let current_is_root = self.segments.len() == 1 && match &self.segments[0] { PathSegment::Static(s) => s.is_empty(), _ => false };

        if current_is_root {
            // Overwrite completely with prefix segments
            self.segments = prefix.segments.clone();
        } else {
            // Insert prefix segments at the beginning of our vector
            let mut new_segments = prefix.segments.clone();
            new_segments.extend(self.segments.drain(..));
            self.segments = new_segments;
        }

        // Recompute the raw original path string safely avoiding double-slashes
        let trimmed_prefix = prefix.original.trim_end_matches('/');
        let trimmed_self = self.original.trim_start_matches('/');
        
        if trimmed_self.is_empty() {
            self.original = prefix.original.clone();
        } else if trimmed_prefix.is_empty() {
            self.original = format!("/{}", trimmed_self);
        } else {
            self.original = format!("{}/{}", trimmed_prefix, trimmed_self);
        }
    }
}

impl PathSegment {
    fn parse_one(segment: &str) -> Self {
        let s = segment.trim();

        if s.starts_with("[[...") && s.ends_with("]]") {
            Self::OptionalCatchAll(s[5..s.len() - 2].to_string())
        } else if s.starts_with("[...") && s.ends_with("]") {
            Self::CatchAll(s[4..s.len() - 1].to_string())
        } else if s.starts_with('[') && s.ends_with(']') {
            Self::Dynamic(s[1..s.len() - 1].to_string())
        } else {
            Self::Static(s.to_string())
        }
    }

    fn to_matchit_single(&self) -> String {
        match self {
            Self::Static(s) => s.trim_matches('/').to_string(),
            Self::Dynamic(name) => format!("{{{}}}", name),
            Self::CatchAll(name) | Self::OptionalCatchAll(name) => format!("{{*{}}}", name),
        }
    }
}