//! Compatibility adapters for the retired C# parser-generator object model.
//!
//! New code should use [`crate::Grammar`], [`crate::Dfa`], and the checked-in
//! grammar generator. These adapters keep mapped callers functional without
//! dynamic method pointers, reflection, or a CLR.

#![allow(clippy::missing_errors_doc)]
#![allow(clippy::must_use_candidate)]
#![allow(clippy::needless_pass_by_value)]
#![allow(clippy::too_many_arguments)]
#![allow(non_snake_case)]

use std::collections::{BTreeMap, BTreeSet, VecDeque};
use std::fmt;
use std::io::Write;
use std::sync::{Arc, Mutex, OnceLock};

use libremetaverse_types::compat::{Hashtable, Object, Utf16CodeUnit};
use regex::Regex as NativeRegex;

use crate::{
    CSymbol, CharacterMatcher, DfaAccept, DfaState, Error, ErrorHandler, Lexer, ObjectList,
    ParseState, Parser, ParserOldAction, ParserSimpleAction, PrecedencePrecType, Production,
    SourceLineInfo, SymbolSet, Transition, YyLexer, YyParser,
};

#[derive(Clone)]
struct Callable<A, R>(Arc<dyn Fn(A) -> Result<R, Error> + Send + Sync>);

impl<A, R> fmt::Debug for Callable<A, R> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("Callable(..)")
    }
}

#[derive(Debug)]
struct AsyncResult<T>(T);

type AsyncCallback = Box<dyn Fn(&dyn std::any::Any) + Send + Sync>;

macro_rules! delegate_one {
    ($name:ident, $arg:ty, $result:ty) => {
        #[derive(Clone, Debug)]
        pub struct $name(Callable<$arg, $result>);

        impl $name {
            pub fn from_fn<F>(function: F) -> Self
            where
                F: Fn($arg) -> Result<$result, Error> + Send + Sync + 'static,
            {
                Self(Callable(Arc::new(function)))
            }

            pub fn new(object: Object, _method: isize) -> Result<Self, Error> {
                object
                    .downcast_ref::<Self>()
                    .cloned()
                    .ok_or(Error::Argument)
            }

            pub fn invoke(&self, argument: $arg) -> Result<$result, Error> {
                (self.0.0)(argument)
            }

            pub fn begin_invoke(
                &self,
                argument: $arg,
                callback: AsyncCallback,
                _state: Object,
            ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
            where
                $result: Send + Sync + 'static,
            {
                let result = AsyncResult(self.invoke(argument)?);
                callback(&result);
                Ok(Box::new(result))
            }

            pub fn end_invoke(
                &self,
                result: Box<dyn std::any::Any + Send + Sync>,
            ) -> Result<$result, Error>
            where
                $result: Send + Sync + 'static,
            {
                result
                    .downcast::<AsyncResult<$result>>()
                    .map(|value| value.0)
                    .map_err(|_| Error::Argument)
            }
        }
    };
}

delegate_one!(Builder, Transition, ());
delegate_one!(Func, Transition, SymbolSet);
delegate_one!(Relation, Transition, Hashtable);
delegate_one!(SCreator, Parser, Object);
delegate_one!(TCreator, Lexer, Object);

#[derive(Clone, Debug)]
pub struct AddToFunc(Callable<(Transition, SymbolSet), ()>);

impl AddToFunc {
    pub fn from_fn<F>(function: F) -> Self
    where
        F: Fn(Transition, SymbolSet) -> Result<(), Error> + Send + Sync + 'static,
    {
        Self(Callable(Arc::new(move |(transition, symbols)| {
            function(transition, symbols)
        })))
    }

    pub fn new(object: Object, _method: isize) -> Result<Self, Error> {
        object
            .downcast_ref::<Self>()
            .cloned()
            .ok_or(Error::Argument)
    }

    pub fn invoke(&self, transition: Transition, symbols: SymbolSet) -> Result<(), Error> {
        (self.0.0)((transition, symbols))
    }

    pub fn begin_invoke(
        &self,
        transition: Transition,
        symbols: SymbolSet,
        callback: AsyncCallback,
        _state: Object,
    ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error> {
        self.invoke(transition, symbols)?;
        let result = AsyncResult(());
        callback(&result);
        Ok(Box::new(result))
    }

    pub fn end_invoke(&self, result: Box<dyn std::any::Any + Send + Sync>) -> Result<(), Error> {
        result
            .downcast::<AsyncResult<()>>()
            .map(|_| ())
            .map_err(|_| Error::Argument)
    }
}

#[derive(Clone, Debug)]
pub struct ObjectListOListEnumerator {
    values: Vec<Object>,
    cursor: Arc<Mutex<Option<usize>>>,
}

impl ObjectListOListEnumerator {
    pub fn new(values: ObjectList) -> Result<Self, Error> {
        Ok(Self {
            values: values.iter().cloned().collect(),
            cursor: Arc::new(Mutex::new(None)),
        })
    }

    pub fn move_next(&self) -> Result<bool, Error> {
        let mut cursor = self.cursor.lock().map_err(|_| Error::InvalidOperation)?;
        let next = cursor.map_or(0, |value| value.saturating_add(1));
        if next < self.values.len() {
            *cursor = Some(next);
            Ok(true)
        } else {
            *cursor = Some(self.values.len());
            Ok(false)
        }
    }

    pub fn reset(&self) -> Result<(), Error> {
        *self.cursor.lock().map_err(|_| Error::InvalidOperation)? = None;
        Ok(())
    }

    pub fn current(&self) -> Object {
        self.cursor
            .lock()
            .ok()
            .and_then(|cursor| cursor.and_then(|index| self.values.get(index).cloned()))
            .unwrap_or(Object::Undefined)
    }
}

#[derive(Clone, Debug)]
pub struct Path {
    pub valid: bool,
    states: Vec<ParseState>,
    spelling: Vec<CSymbol>,
}

impl Path {
    pub fn new_with_parse_state_array(states: Vec<ParseState>) -> Result<Self, Error> {
        if states.is_empty() {
            return Err(Error::Argument);
        }
        let spelling = states
            .iter()
            .take(states.len().saturating_sub(1))
            .map(|state| state.m_accessing_symbol.clone())
            .collect();
        Ok(Self {
            valid: true,
            states,
            spelling,
        })
    }

    pub fn new_with_parse_state_c_symbol_array(
        state: ParseState,
        symbols: Vec<CSymbol>,
    ) -> Result<Self, Error> {
        let mut states = vec![state.clone()];
        let mut current = state;
        let mut valid = true;
        for symbol in &symbols {
            if let Ok(transition) = current.get_transition(symbol.clone()) {
                current = *transition.m_ps.clone();
                states.push(current.clone());
            } else {
                valid = false;
                states.push(current.clone());
            }
        }
        Ok(Self {
            valid,
            states,
            spelling: symbols,
        })
    }

    pub fn new_with_c_symbol_array(symbols: Vec<CSymbol>) -> Result<Self, Error> {
        if symbols.is_empty() {
            return Err(Error::Argument);
        }
        Self::new_with_parse_state_c_symbol_array(ParseState::compatibility_numbered(0), symbols)
    }

    pub fn spelling(&self) -> Vec<CSymbol> {
        self.spelling.clone()
    }

    pub fn top(&self) -> ParseState {
        self.states
            .last()
            .cloned()
            .unwrap_or_else(|| ParseState::compatibility_numbered(0))
    }
}

#[derive(Clone, Debug)]
enum NfaMatcher {
    Exact(u16),
    Uppercase(u16),
    Predicate(Regex),
}

#[derive(Clone, Debug)]
struct NfaArc {
    matcher: NfaMatcher,
    target: i32,
}

#[derive(Clone, Debug, Default)]
struct NfaNodeData {
    arcs: Vec<NfaArc>,
    epsilon: Vec<i32>,
}

#[derive(Clone, Debug, Default)]
struct TokenGeneratorState {
    next_state: i32,
    nodes: BTreeMap<i32, NfaNodeData>,
}

#[derive(Clone, Debug)]
pub struct TokensGen {
    pub defines: Hashtable,
    pub m_tokens: YyLexer,
    pub states: ObjectList,
    pub m_outname: String,
    state: Arc<Mutex<TokenGeneratorState>>,
}

impl TokensGen {
    pub fn new(error_handler: ErrorHandler) -> Result<Self, Error> {
        Ok(Self {
            defines: Hashtable::default(),
            m_tokens: YyLexer::new(error_handler)?,
            states: ObjectList::default(),
            m_outname: "tokens".to_owned(),
            state: Arc::new(Mutex::new(TokenGeneratorState::default())),
        })
    }

    pub fn fix_actions(&self, source: String) -> Result<String, Error> {
        Ok(source
            .replace("yybegin", "yym.yy_begin")
            .replace("yyl", &format!("(({})yym)", self.m_outname)))
    }

    pub fn new_state(&self) -> Result<i32, Error> {
        let mut state = self.state.lock().map_err(|_| Error::InvalidOperation)?;
        state.next_state = state
            .next_state
            .checked_add(1)
            .ok_or(Error::IndexOutOfRange)?;
        let number = state.next_state;
        state.nodes.entry(number).or_default();
        Ok(number)
    }

    fn add_arc(&self, from: i32, arc: NfaArc) -> Result<(), Error> {
        self.state
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .nodes
            .entry(from)
            .or_default()
            .arcs
            .push(arc);
        Ok(())
    }

    fn add_epsilon(&self, from: i32, target: i32) -> Result<(), Error> {
        self.state
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .nodes
            .entry(from)
            .or_default()
            .epsilon
            .push(target);
        Ok(())
    }
}

#[derive(Clone, Debug)]
pub struct LNode {
    pub m_state: i32,
    pub m_tks: TokensGen,
}

impl LNode {
    pub fn new(tokens: TokensGen) -> Result<Self, Error> {
        let state = tokens.new_state()?;
        Ok(Self {
            m_state: state,
            m_tks: tokens,
        })
    }
}

#[derive(Clone, Debug)]
pub struct NfaNode {
    pub m_arcs: ObjectList,
    pub m_eps: ObjectList,
    pub m_s_terminal: String,
    pub node: LNode,
}

impl NfaNode {
    pub fn new(tokens: TokensGen) -> Result<Self, Error> {
        Ok(Self {
            m_arcs: ObjectList::default(),
            m_eps: ObjectList::default(),
            m_s_terminal: String::new(),
            node: LNode::new(tokens)?,
        })
    }

    pub fn add_arc(&self, unit: Utf16CodeUnit, next: NfaNode) -> Result<(), Error> {
        self.node.m_tks.add_arc(
            self.node.m_state,
            NfaArc {
                matcher: NfaMatcher::Exact(unit.0),
                target: next.node.m_state,
            },
        )
    }

    pub fn add_u_arc(&self, unit: Utf16CodeUnit, next: NfaNode) -> Result<(), Error> {
        self.node.m_tks.add_arc(
            self.node.m_state,
            NfaArc {
                matcher: NfaMatcher::Uppercase(unit.0),
                target: next.node.m_state,
            },
        )
    }

    pub fn add_arc_ex(&self, regex: Regex, next: NfaNode) -> Result<(), Error> {
        self.node.m_tks.add_arc(
            self.node.m_state,
            NfaArc {
                matcher: NfaMatcher::Predicate(regex),
                target: next.node.m_state,
            },
        )
    }

    pub fn add_eps(&self, next: NfaNode) -> Result<(), Error> {
        self.node
            .m_tks
            .add_epsilon(self.node.m_state, next.node.m_state)
    }

    pub fn add_target(&self, unit: Utf16CodeUnit, mut next: crate::Dfa) -> Result<(), Error> {
        let state = self
            .node
            .m_tks
            .state
            .lock()
            .map_err(|_| Error::InvalidOperation)?;
        let Some(node) = state.nodes.get(&self.node.m_state) else {
            return Ok(());
        };
        for arc in &node.arcs {
            let matched = match &arc.matcher {
                NfaMatcher::Exact(expected) => *expected == unit.0,
                NfaMatcher::Uppercase(expected) => String::from_utf16(&[unit.0])
                    .ok()
                    .and_then(|value| value.chars().next())
                    .is_some_and(|value| {
                        value
                            .to_uppercase()
                            .next()
                            .is_some_and(|upper| upper as u32 == u32::from(*expected))
                    }),
                NfaMatcher::Predicate(regex) => regex.match__with_char(unit)?,
            };
            if matched {
                next.m_map
                    .0
                    .insert(Object::Integer(arc.target), Object::Boolean(true));
            }
        }
        Ok(())
    }
}

#[derive(Clone, Debug)]
pub struct Nfa {
    pub m_end: NfaNode,
    pub start: NfaNode,
    regex: Arc<Mutex<Option<Regex>>>,
}

impl Nfa {
    pub fn new_with_tokens_gen(tokens: TokensGen) -> Result<Self, Error> {
        Ok(Self {
            start: NfaNode::new(tokens.clone())?,
            m_end: NfaNode::new(tokens)?,
            regex: Arc::new(Mutex::new(None)),
        })
    }

    pub fn new_with_tokens_gen_regex(tokens: TokensGen, regex: Regex) -> Result<Self, Error> {
        let nfa = Self::new_with_tokens_gen(tokens)?;
        regex.build(nfa.clone())?;
        Ok(nfa)
    }

    fn set_regex(&self, regex: Regex) -> Result<(), Error> {
        *self.regex.lock().map_err(|_| Error::InvalidOperation)? = Some(regex.clone());
        self.start.add_arc_ex(regex, self.m_end.clone())
    }

    pub(crate) fn regex_source(&self) -> Result<Option<String>, Error> {
        Ok(self
            .regex
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .as_ref()
            .map(|regex| regex.source.clone()))
    }

    pub(crate) fn deterministic_states(&self, accept: DfaAccept) -> Result<Vec<DfaState>, Error> {
        const MAX_GENERATED_DFA_STATES: usize = 4_096;

        fn closure(
            nodes: &BTreeMap<i32, NfaNodeData>,
            seeds: impl IntoIterator<Item = i32>,
        ) -> BTreeSet<i32> {
            let mut result = BTreeSet::new();
            let mut pending = VecDeque::from_iter(seeds);
            while let Some(state) = pending.pop_front() {
                if !result.insert(state) {
                    continue;
                }
                if let Some(node) = nodes.get(&state) {
                    pending.extend(node.epsilon.iter().copied());
                }
            }
            result
        }

        fn matches(matcher: &NfaMatcher, unit: u16) -> Result<bool, Error> {
            Ok(match matcher {
                NfaMatcher::Exact(expected) => unit == *expected,
                NfaMatcher::Uppercase(expected) => String::from_utf16(&[unit])
                    .ok()
                    .and_then(|value| value.chars().next())
                    .is_some_and(|value| {
                        value
                            .to_uppercase()
                            .next()
                            .is_some_and(|upper| upper as u32 == u32::from(*expected))
                    }),
                NfaMatcher::Predicate(regex) => regex.match__with_char(Utf16CodeUnit(unit))?,
            })
        }

        let generator = self
            .start
            .node
            .m_tks
            .state
            .lock()
            .map_err(|_| Error::InvalidOperation)?;
        let start = closure(&generator.nodes, [self.start.node.m_state]);
        let mut indexes = BTreeMap::from([(start.clone(), 0usize)]);
        let mut pending = VecDeque::from([start]);
        let mut states = Vec::new();
        while let Some(subset) = pending.pop_front() {
            let mut targets = BTreeMap::<BTreeSet<i32>, BTreeSet<u16>>::new();
            for unit in 0..=u16::MAX {
                let mut destination = BTreeSet::new();
                for state in &subset {
                    if let Some(node) = generator.nodes.get(state) {
                        for arc in &node.arcs {
                            if matches(&arc.matcher, unit)? {
                                destination.insert(arc.target);
                            }
                        }
                    }
                }
                if !destination.is_empty() {
                    targets
                        .entry(closure(&generator.nodes, destination))
                        .or_default()
                        .insert(unit);
                }
            }
            let mut transitions = Vec::new();
            for (target, units) in targets {
                let index = if let Some(index) = indexes.get(&target).copied() {
                    index
                } else {
                    if indexes.len() >= MAX_GENERATED_DFA_STATES {
                        return Err(Error::IndexOutOfRange);
                    }
                    let index = indexes.len();
                    indexes.insert(target.clone(), index);
                    pending.push_back(target);
                    index
                };
                transitions.push((CharacterMatcher::Set(units), index));
            }
            states.push(DfaState {
                transitions,
                accept: subset
                    .contains(&self.m_end.node.m_state)
                    .then(|| accept.clone()),
            });
        }
        if states.iter().all(|state| state.accept.is_none()) {
            return Err(Error::Argument);
        }
        Ok(states)
    }
}

#[derive(Clone)]
pub struct Serialiser {
    input: Option<Arc<Vec<i32>>>,
    output: Option<Arc<Mutex<Box<dyn Write + Send>>>>,
    position: Arc<Mutex<usize>>,
    column: Arc<Mutex<usize>>,
}

impl fmt::Debug for Serialiser {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter
            .debug_struct("Serialiser")
            .field("encode", &self.encode())
            .field("position", &self.position.lock().map_or(0, |value| *value))
            .finish_non_exhaustive()
    }
}

impl Serialiser {
    pub fn new_with_text_writer(output: Box<dyn Write + Send>) -> Result<Self, Error> {
        Ok(Self {
            input: None,
            output: Some(Arc::new(Mutex::new(output))),
            position: Arc::new(Mutex::new(0)),
            column: Arc::new(Mutex::new(0)),
        })
    }

    pub fn new_with_int32_array(input: Vec<i32>) -> Result<Self, Error> {
        Ok(Self {
            input: Some(Arc::new(input)),
            output: None,
            position: Arc::new(Mutex::new(0)),
            column: Arc::new(Mutex::new(0)),
        })
    }

    pub const fn encode(&self) -> bool {
        self.output.is_some()
    }

    pub fn read(&self) -> Result<i32, Error> {
        let input = self.input.as_ref().ok_or(Error::InvalidOperation)?;
        let mut position = self.position.lock().map_err(|_| Error::InvalidOperation)?;
        let value = *input.get(*position).ok_or(Error::IndexOutOfRange)?;
        *position += 1;
        Ok(value)
    }

    pub fn write(&self, value: i32) -> Result<(), Error> {
        let output = self.output.as_ref().ok_or(Error::InvalidOperation)?;
        let mut output = output.lock().map_err(|_| Error::InvalidOperation)?;
        let mut column = self.column.lock().map_err(|_| Error::InvalidOperation)?;
        if *column == 5 {
            output
                .write_all(b"\n")
                .map_err(|_| Error::InvalidOperation)?;
            *column = 0;
        }
        write!(output, "{value},").map_err(|_| Error::InvalidOperation)?;
        *column += 1;
        Ok(())
    }

    pub fn serialise(&self, object: Object) -> Result<(), Error> {
        match object {
            Object::Undefined => self.write(0),
            Object::Integer(value) => {
                self.write(1)?;
                self.write(value)
            }
            Object::Boolean(value) => {
                self.write(2)?;
                self.write(i32::from(value))
            }
            Object::String(value) => {
                self.write(4)?;
                let bytes = value
                    .encode_utf16()
                    .flat_map(u16::to_le_bytes)
                    .collect::<Vec<_>>();
                self.write(i32::try_from(bytes.len()).map_err(|_| Error::IndexOutOfRange)?)?;
                for byte in bytes {
                    self.write(i32::from(byte))?;
                }
                Ok(())
            }
            Object::Array(values) => {
                self.write(24)?;
                self.write(i32::try_from(values.len()).map_err(|_| Error::IndexOutOfRange)?)?;
                for value in values {
                    self.serialise(value)?;
                }
                Ok(())
            }
            Object::Map(values) => {
                self.write(25)?;
                self.write(i32::try_from(values.len()).map_err(|_| Error::IndexOutOfRange)?)?;
                let mut values = values.into_iter().collect::<Vec<_>>();
                values.sort_by(|left, right| left.0.cmp(&right.0));
                for (key, value) in values {
                    self.serialise(Object::String(key))?;
                    self.serialise(value)?;
                }
                Ok(())
            }
            _ => Err(Error::Argument),
        }
    }

    pub fn deserialise(&self) -> Result<Object, Error> {
        match self.read()? {
            0 => Ok(Object::Undefined),
            1 => Ok(Object::Integer(self.read()?)),
            2 => Ok(Object::Boolean(self.read()? != 0)),
            4 => {
                let count = usize::try_from(self.read()?).map_err(|_| Error::Argument)?;
                if count % 2 != 0 {
                    return Err(Error::Parse {
                        position: count,
                        context: "odd UTF-16 byte count",
                    });
                }
                let mut bytes = Vec::with_capacity(count);
                for _ in 0..count {
                    bytes.push(u8::try_from(self.read()?).map_err(|_| Error::Argument)?);
                }
                let units = bytes
                    .chunks_exact(2)
                    .map(|pair| u16::from_le_bytes([pair[0], pair[1]]))
                    .collect::<Vec<_>>();
                String::from_utf16(&units)
                    .map(Object::String)
                    .map_err(|_| Error::Parse {
                        position: 0,
                        context: "invalid UTF-16 string",
                    })
            }
            24 => {
                let count = usize::try_from(self.read()?).map_err(|_| Error::Argument)?;
                let mut values = Vec::with_capacity(count);
                for _ in 0..count {
                    values.push(self.deserialise()?);
                }
                Ok(Object::Array(values))
            }
            25 => {
                let count = usize::try_from(self.read()?).map_err(|_| Error::Argument)?;
                let mut values = std::collections::HashMap::with_capacity(count);
                for _ in 0..count {
                    let Object::String(key) = self.deserialise()? else {
                        return Err(Error::Argument);
                    };
                    values.insert(key, self.deserialise()?);
                }
                Ok(Object::Map(values))
            }
            _ => Err(Error::Parse {
                position: self.position.lock().map_or(0, |value| *value),
                context: "unknown serialization tag",
            }),
        }
    }

    pub fn version_check(&self) -> Result<(), Error> {
        if self.encode() {
            self.serialise(Object::String("4.5".to_owned()))
        } else if self.deserialise()? == Object::String("4.5".to_owned()) {
            Ok(())
        } else {
            Err(Error::Parse {
                position: 0,
                context: "expected serialization version 4.5",
            })
        }
    }
}

#[derive(Clone)]
pub struct GenBase {
    pub last_symbol: i32,
    pub erh: ErrorHandler,
    pub m_out_file: Arc<Mutex<Box<dyn Write + Send>>>,
    pub m_outname: String,
    pub m_prod: Production,
}

impl fmt::Debug for GenBase {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter
            .debug_struct("GenBase")
            .field("last_symbol", &self.last_symbol)
            .field("outname", &self.m_outname)
            .field("production", &self.m_prod)
            .finish_non_exhaustive()
    }
}

impl GenBase {
    pub fn new(error_handler: ErrorHandler, output: Box<dyn Write + Send>) -> Result<Self, Error> {
        let symbols = SymbolsGen::new(error_handler.clone())?;
        Ok(Self {
            last_symbol: 2,
            erh: error_handler,
            m_out_file: Arc::new(Mutex::new(output)),
            m_outname: "tokens".to_owned(),
            m_prod: Production::new_with_symbols_gen(symbols)?,
        })
    }

    pub fn white(&self, buffer: String, offset: &mut i32, max: i32) -> Result<bool, Error> {
        scan_while(&buffer, offset, max, |value| matches!(value, b' ' | b'\t'))
    }

    pub fn non_white(&self, buffer: String, offset: &mut i32, max: i32) -> Result<bool, Error> {
        scan_while(&buffer, offset, max, |value| !matches!(value, b' ' | b'\t'))
    }

    pub fn source_line_info(&self, position: i32) -> Result<SourceLineInfo, Error> {
        SourceLineInfo::new_with_int32(position)
    }

    pub fn line(&self, position: i32) -> Result<i32, Error> {
        Ok(self.source_line_info(position)?.line_number)
    }

    pub fn position(&self, position: i32) -> Result<i32, Error> {
        Ok(self.source_line_info(position)?.raw_char_position)
    }

    pub fn saypos(&self, position: i32) -> Result<String, Error> {
        Ok(self.source_line_info(position)?.to_string())
    }

    pub fn error(&self, number: i32, position: i32, message: String) -> Result<(), Error> {
        let exception =
            crate::CSToolsFatalException::new_with_int32_source_line_info_string_string(
                number,
                self.source_line_info(position)?,
                String::new(),
                message,
            )?;
        self.erh.clone().error(exception.0)
    }

    pub fn emit_class_defin(
        &self,
        buffer: String,
        offset: &mut i32,
        max: i32,
        _input: crate::CsReader,
        default_base: String,
        base: &mut String,
        name: &mut String,
        lexer: bool,
    ) -> Result<i32, Error> {
        if lexer {
            self.non_white(buffer.clone(), offset, max)?;
        }
        self.white(buffer.clone(), offset, max)?;
        let bytes = buffer.as_bytes();
        let limit = usize::try_from(max)
            .map_err(|_| Error::Argument)?
            .min(bytes.len());
        let mut index = usize::try_from(*offset).map_err(|_| Error::Argument)?;
        let start = index;
        while index < limit && !matches!(bytes[index], b'{' | b':' | b';' | b' ' | b'\t' | b'\n') {
            index += 1;
        }
        buffer
            .get(start..index)
            .ok_or(Error::Argument)?
            .clone_into(name);
        if name.is_empty() {
            return Err(Error::Parse {
                position: start,
                context: "class name is missing",
            });
        }
        *base = default_base;
        while index < limit && matches!(bytes[index], b' ' | b'\t') {
            index += 1;
        }
        if bytes.get(index) == Some(&b':') {
            index += 1;
            while index < limit && matches!(bytes[index], b' ' | b'\t') {
                index += 1;
            }
            let base_start = index;
            while index < limit && !matches!(bytes[index], b'{' | b';' | b' ' | b'\t' | b'\n') {
                index += 1;
            }
            buffer
                .get(base_start..index)
                .ok_or(Error::Argument)?
                .clone_into(base);
        }
        *offset = i32::try_from(index).map_err(|_| Error::IndexOutOfRange)?;
        let number = self
            .last_symbol
            .checked_add(1)
            .ok_or(Error::IndexOutOfRange)?;
        let mut output = self
            .m_out_file
            .lock()
            .map_err(|_| Error::InvalidOperation)?;
        writeln!(
            output,
            "// generated {name}={number}\npub struct {name}; // base: {base}"
        )
        .map_err(|_| Error::InvalidOperation)?;
        Ok(number)
    }
}

fn scan_while<F>(buffer: &str, offset: &mut i32, max: i32, predicate: F) -> Result<bool, Error>
where
    F: Fn(u8) -> bool,
{
    let bytes = buffer.as_bytes();
    let limit = usize::try_from(max)
        .map_err(|_| Error::Argument)?
        .min(bytes.len());
    let mut index = usize::try_from(*offset).map_err(|_| Error::Argument)?;
    if index > limit {
        return Err(Error::IndexOutOfRange);
    }
    while index < limit && predicate(bytes[index]) {
        index += 1;
    }
    *offset = i32::try_from(index).map_err(|_| Error::IndexOutOfRange)?;
    Ok(index < limit)
}

#[derive(Clone, Debug, Default)]
struct SymbolsGeneratorState {
    associations: Vec<(PrecedencePrecType, i32)>,
    class_definitions: Vec<String>,
    directives: Vec<String>,
    actions: Vec<String>,
}

#[derive(Clone, Debug)]
pub struct SymbolType {
    pub name: String,
    pub defined: bool,
    registry: Arc<Mutex<BTreeMap<String, SymbolType>>>,
}

impl SymbolType {
    fn root() -> Self {
        Self {
            name: String::new(),
            defined: false,
            registry: Arc::new(Mutex::new(BTreeMap::new())),
        }
    }

    pub fn new_with_symbols_gen_string(symbols: SymbolsGen, name: String) -> Result<Self, Error> {
        Self::new_with_symbols_gen_string_boolean(symbols, name, false)
    }

    pub fn new_with_symbols_gen_string_boolean(
        symbols: SymbolsGen,
        name: String,
        defined: bool,
    ) -> Result<Self, Error> {
        if name.is_empty() {
            return Err(Error::Argument);
        }
        let value = Self {
            name: name.clone(),
            defined,
            registry: symbols.stypes.registry.clone(),
        };
        value
            .registry
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .insert(name, value.clone());
        Ok(value)
    }

    pub fn find(&self, name: String) -> Result<Self, Error> {
        self.registry
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .get(&name)
            .cloned()
            .ok_or(Error::InvalidOperation)
    }
}

#[derive(Clone, Debug)]
pub struct SymbolsGen {
    pub action: i32,
    pub lahead: SymbolSet,
    pub m_lalr_parser: bool,
    pub m_lexer: Lexer,
    pub m_symbols: YyParser,
    pub m_trans: i32,
    pub pno: i32,
    pub prods: ObjectList,
    pub stypes: SymbolType,
    state: Arc<Mutex<SymbolsGeneratorState>>,
}

impl SymbolsGen {
    pub fn new(error_handler: ErrorHandler) -> Result<Self, Error> {
        let lexer = Lexer::new(YyLexer::new(error_handler.clone())?)?;
        let mut parser = YyParser::new()?;
        parser.erh = error_handler;
        Ok(Self {
            action: 0,
            lahead: SymbolSet::compatibility_empty(),
            m_lalr_parser: true,
            m_lexer: lexer,
            m_symbols: parser,
            m_trans: 0,
            pno: 0,
            prods: ObjectList::default(),
            stypes: SymbolType::root(),
            state: Arc::new(Mutex::new(SymbolsGeneratorState::default())),
        })
    }

    pub fn assoc_type(&self, kind: PrecedencePrecType, number: i32) -> Result<(), Error> {
        if number < 0 {
            return Err(Error::Argument);
        }
        self.state
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .associations
            .push((kind, number));
        Ok(())
    }

    pub fn class_definition(&self, source: String) -> Result<(), Error> {
        if source.trim().is_empty() {
            return Err(Error::Argument);
        }
        self.state
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .class_definitions
            .push(source);
        Ok(())
    }

    pub fn copy_segment(&self) -> Result<(), Error> {
        let segment = self.m_lexer.yytext.clone();
        self.state
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .directives
            .push(segment);
        Ok(())
    }

    pub fn declare(&self) -> Result<(), Error> {
        let declaration = self.m_lexer.yytext.trim().to_owned();
        if declaration.is_empty() {
            return Err(Error::Argument);
        }
        self.state
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .directives
            .push(declaration);
        Ok(())
    }

    pub fn find(&self, symbol: CSymbol) -> Result<bool, Error> {
        Ok(self
            .m_symbols
            .symbols
            .0
            .values()
            .any(|value| matches!(value, Object::Integer(number) if *number == symbol.m_yynum)))
    }

    pub fn old_action(&self, action: ParserOldAction) -> Result<(), Error> {
        self.state
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .actions
            .push(format!("old:{}", action.act_num()?));
        Ok(())
    }

    pub fn simple_action(&self, action: ParserSimpleAction) -> Result<(), Error> {
        self.state
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .actions
            .push(action.type_str()?);
        Ok(())
    }

    pub fn parser_directive(&self) -> Result<(), Error> {
        self.state
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .directives
            .push("parser".to_owned());
        Ok(())
    }

    pub fn set_namespace(&self) -> Result<(), Error> {
        let namespace = self.m_lexer.yytext.trim();
        if namespace.is_empty() {
            return Err(Error::Argument);
        }
        self.state
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .directives
            .push(format!("namespace:{namespace}"));
        Ok(())
    }

    pub fn set_start_symbol(&self) -> Result<(), Error> {
        let start = self.m_lexer.yytext.trim();
        if start.is_empty() {
            return Err(Error::Argument);
        }
        self.state
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .directives
            .push(format!("start:{start}"));
        Ok(())
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TokClassDef {
    pub m_implement: String,
    pub m_initialisation: String,
    pub m_name: String,
    pub m_ref_token: String,
    pub m_yynum: i32,
}

impl TokClassDef {
    pub fn new(generator: GenBase, name: String, base: String) -> Result<Self, Error> {
        if name.is_empty() || base.is_empty() {
            return Err(Error::Argument);
        }
        Ok(Self {
            m_implement: String::new(),
            m_initialisation: String::new(),
            m_name: name,
            m_ref_token: base,
            m_yynum: generator
                .last_symbol
                .checked_add(1)
                .ok_or(Error::IndexOutOfRange)?,
        })
    }

    pub fn serialise(object: Object, serialiser: Serialiser) -> Result<Object, Error> {
        if serialiser.encode() {
            let value = object.downcast_ref::<Self>().ok_or(Error::Argument)?;
            serialiser.serialise(Object::String(value.m_name.clone()))?;
            serialiser.serialise(Object::Integer(value.m_yynum))?;
            Ok(Object::Undefined)
        } else {
            let Object::String(name) = serialiser.deserialise()? else {
                return Err(Error::Argument);
            };
            let Object::Integer(number) = serialiser.deserialise()? else {
                return Err(Error::Argument);
            };
            Ok(Object::opaque(Self {
                m_name: name,
                m_yynum: number,
                m_implement: String::new(),
                m_initialisation: String::new(),
                m_ref_token: "TOKEN".to_owned(),
            }))
        }
    }
}

fn symbol_factories() -> &'static Mutex<BTreeMap<String, SCreator>> {
    static FACTORIES: OnceLock<Mutex<BTreeMap<String, SCreator>>> = OnceLock::new();
    FACTORIES.get_or_init(|| Mutex::new(BTreeMap::new()))
}

fn token_factories() -> &'static Mutex<BTreeMap<String, TCreator>> {
    static FACTORIES: OnceLock<Mutex<BTreeMap<String, TCreator>>> = OnceLock::new();
    FACTORIES.get_or_init(|| Mutex::new(BTreeMap::new()))
}

#[derive(Clone, Debug)]
pub struct Sfactory {
    name: String,
}

impl Sfactory {
    pub fn new(_symbols: YyParser, class_name: String, creator: SCreator) -> Result<Self, Error> {
        if class_name.is_empty() {
            return Err(Error::Argument);
        }
        symbol_factories()
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .insert(class_name.clone(), creator);
        Ok(Self { name: class_name })
    }

    pub fn create(class_name: String, parser: Parser) -> Result<Object, Error> {
        let factories = symbol_factories()
            .lock()
            .map_err(|_| Error::InvalidOperation)?;
        let mut candidate = class_name.as_str();
        loop {
            if let Some(factory) = factories.get(candidate) {
                return factory.invoke(parser);
            }
            let Some((base, _)) = candidate.rsplit_once('_') else {
                break;
            };
            candidate = base;
        }
        Err(Error::InvalidOperation)
    }

    pub fn name(&self) -> &str {
        &self.name
    }
}

#[derive(Clone, Debug)]
pub struct Tfactory {
    name: String,
}

impl Tfactory {
    pub fn new(_tokens: YyLexer, class_name: String, creator: TCreator) -> Result<Self, Error> {
        if class_name.is_empty() {
            return Err(Error::Argument);
        }
        token_factories()
            .lock()
            .map_err(|_| Error::InvalidOperation)?
            .insert(class_name.clone(), creator);
        Ok(Self { name: class_name })
    }

    pub fn create(class_name: String, lexer: Lexer) -> Result<Object, Error> {
        let factories = token_factories()
            .lock()
            .map_err(|_| Error::InvalidOperation)?;
        let mut candidate = class_name.as_str();
        loop {
            if let Some(factory) = factories.get(candidate) {
                return factory.invoke(lexer);
            }
            let Some((base, _)) = candidate.rsplit_once('_') else {
                break;
            };
            candidate = base;
        }
        Err(Error::InvalidOperation)
    }

    pub fn name(&self) -> &str {
        &self.name
    }
}

/// Portable regular-expression adapter. Matching is anchored at the requested
/// input position, as in the original lexer generator.
#[derive(Clone)]
pub struct Regex {
    source: String,
    compiled: NativeRegex,
    pub m_sub: Option<Box<Regex>>,
}

impl fmt::Debug for Regex {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.debug_tuple("Regex").field(&self.source).finish()
    }
}

impl Regex {
    pub fn new(_tokens: TokensGen, position: i32, source: String) -> Result<Self, Error> {
        const MAX_REGEX_UNITS: usize = 1_048_576;
        if position < 0 {
            return Err(Error::Argument);
        }
        if source.encode_utf16().count() > MAX_REGEX_UNITS {
            return Err(Error::IndexOutOfRange);
        }
        // `position` locates this expression in the generator input for
        // diagnostics; it is not an offset into the expression itself.
        let compiled = NativeRegex::new(&format!("^(?:{source})")).map_err(|_| Error::Parse {
            position: usize::try_from(position).unwrap_or(0),
            context: "invalid lexer regular expression",
        })?;
        Ok(Self {
            source,
            compiled,
            m_sub: None,
        })
    }

    pub fn build(&self, nfa: Nfa) -> Result<(), Error> {
        nfa.set_regex(self.clone())
    }

    pub fn match__with_char(&self, unit: Utf16CodeUnit) -> Result<bool, Error> {
        // `System.Char` can hold an unpaired surrogate. Rust strings cannot,
        // and no valid Unicode regex atom should match one, so it is a clean
        // mismatch rather than a malformed-regex failure.
        let Ok(text) = String::from_utf16(&[unit.0]) else {
            return Ok(false);
        };
        Ok(self
            .compiled
            .find(&text)
            .is_some_and(|value| value.end() == text.len()))
    }

    pub fn match__with_string(&self, value: String) -> Result<i32, Error> {
        self.match__with_string_int32_int32(
            value.clone(),
            0,
            i32::try_from(value.encode_utf16().count()).map_err(|_| Error::IndexOutOfRange)?,
        )
    }

    pub fn match__with_string_int32_int32(
        &self,
        value: String,
        position: i32,
        max: i32,
    ) -> Result<i32, Error> {
        let units = value.encode_utf16().collect::<Vec<_>>();
        let position = usize::try_from(position).map_err(|_| Error::Argument)?;
        let max = usize::try_from(max).map_err(|_| Error::Argument)?;
        if position > units.len() || position > max {
            return Ok(-1);
        }
        let end = max.min(units.len());
        let text = String::from_utf16(&units[position..end]).map_err(|_| Error::Argument)?;
        let Some(found) = self.compiled.find(&text) else {
            return Ok(-1);
        };
        i32::try_from(text[..found.end()].encode_utf16().count())
            .map_err(|_| Error::IndexOutOfRange)
    }

    pub fn print(&self, mut output: Box<dyn Write + Send>) -> Result<(), Error> {
        output
            .write_all(self.source.as_bytes())
            .map_err(|_| Error::InvalidOperation)
    }
}
