#![doc = include_str!("readme.md")]

/// Type of highlighting to apply for TOML code.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HighlightKind {
    /// Configuration key.
    Key,
    /// String literal.
    String,
    /// Numeric literal.
    Number,
    /// Boolean literal (true/false).
    Boolean,
    /// Comment block or line.
    Comment,
    /// Date-time literal.
    DateTime,
    /// Punctuation symbols (e.g., [ ] { } = .).
    Punctuation,
}

/// Highlighter trait for processing source text.
pub trait Highlighter {
    /// Highlights the given text and returns a list of ranges with their corresponding highlight kind.
    fn highlight(&self, text: &str) -> Vec<(usize, usize, HighlightKind)>;
}

/// TOML-specific syntax highlighter.
pub struct TomlHighlighter {
    /// Whether to use the full parser for more accurate highlighting.
    pub use_parser: bool,
}

impl Default for TomlHighlighter {
    fn default() -> Self {
        Self { use_parser: false }
    }
}

impl TomlHighlighter {
    /// Creates a new `TomlHighlighter` with default settings.
    pub fn new() -> Self {
        Self::default()
    }

    /// Internal method to highlight comments in the text.
    fn highlight_comments(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
        let mut highlights = Vec::new();
        let mut start = 0;
        while let Some(pos) = text[start..].find('#') {
            let absolute_pos = start + pos;
            let end_of_line = text[absolute_pos..].find('\n').map(|i| absolute_pos + i).unwrap_or(text.len());
            highlights.push((absolute_pos, end_of_line, HighlightKind::Comment));
            start = end_of_line;
        }
        highlights
    }

    /// Internal method to highlight strings in the text.
    fn highlight_strings(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
        let mut highlights = Vec::new();
        let mut chars = text.char_indices().peekable();

        while let Some((i, ch)) = chars.next() {
            if ch == '"' || ch == '\'' {
                let quote = ch;
                let start = i;
                let mut end = i + 1;
                let mut escaped = false;

                while let Some((j, next_ch)) = chars.next() {
                    end = j + next_ch.len_utf8();
                    if escaped {
                        escaped = false;
                    }
                    else if next_ch == '\\' && quote == '"' {
                        escaped = true;
                    }
                    else if next_ch == quote {
                        break;
                    }
                }
                highlights.push((start, end, HighlightKind::String));
            }
        }
        highlights
    }
}

impl Highlighter for TomlHighlighter {
    fn highlight(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
        let mut highlights = Vec::new();
        highlights.extend(self.highlight_comments(text));
        highlights.extend(self.highlight_strings(text));
        // TODO: Add more highlighters for keys, numbers, booleans, etc.
        highlights.sort_by_key(|h| h.0);
        highlights
    }
}
