use u_fst::raw::{Fst, Output};

use crate::element::{Elements, Range};
use crate::weights::EXPLICIT_WEIGHTS;

const TABLE: Fst<&'static [u8]> =
    Fst::new_unchecked(include_bytes!(concat!(env!("OUT_DIR"), "/table.fst")));

pub(crate) fn lookup(value: &[char]) -> Option<(Elements, usize)> {
    let mut node = TABLE.root();
    let mut out = Output::zero();

    let mut last_match = None;

    'char: for (i, &c) in value.iter().enumerate() {
        for b in (c as u32).to_ne_bytes() {
            if let Some(trans_index) = node.find_input(b) {
                let t = node.transition(trans_index);

                node = TABLE.node(t.addr);
                out = out.cat(t.out);

                if node.is_final() {
                    last_match = Some((out.cat(node.final_output()).value(), i));
                }
            } else {
                break 'char;
            }
        }
    }

    last_match.map(|(data, idx)| {
        (
            if data & 0x1 == 1 {
                Elements {
                    buf: &[],
                    cur: data,
                }
            } else {
                let r = Range(data >> 1);

                let (first, buf) = EXPLICIT_WEIGHTS[r.start()..r.end()].split_at(1);

                Elements { buf, cur: first[0] }
            },
            idx,
        )
    })
}
