use crate::prelude::*;
use crate::text::TextNode;

/// # Symbol
/// A symbol identified by symmie notation.
///
/// Symmie is Typst's notation for Unicode symbols. It is based on the idea of
/// _modifiers._ Many symbols in Unicode are very similar. In symmie, such
/// groups of symbols share a common name. To distinguish between the symbols
/// within a group, we use one or multiple modifiers that are separated from the
/// name by colons.
///
/// There is currently no easily viewable list of all names, but in the
/// meantime you can rely on the autocompletion in Typst's web editor.
///
/// ## Syntax
/// This function also has dedicated syntax: In markup, you can enclose symmie
/// notation within colons to produce a symbol. And in math, you can just write
/// the notation directly. There, all letter sequence of length at least two are
/// automatically parsed as symbols (unless a variable of that name is defined).
///
/// Additionally, some very common but hard to type symbols can be expressed with
/// dedicated shortcuts. These are:
///
/// | Symmie      | Shorthand | Result |
/// | ----------- | --------- | ------ |
/// | `dots:b`    | `...`     | …      |
/// | `dash:en`   | `---`     | –      |
/// | `dash:em`   | `--`      | —      |
/// | none yet    | `-?`      | A soft hyphen |
/// | none yet    | `~`       | A non breaking space |
///
/// Within math mode, additional shorthands are available:
///
/// | Symmie             | Shorthand | Result |
/// | ------------------ | --------- | ------ |
/// | `arrow:r`          | `->`      | `→`    |
/// | `arrow:r:double`   | `=>`      | `⇒`    |
/// | `arrow:l`          | `<-`      | `←`    |
/// | `arrow:r:bar`      | <code>&VerticalLine;-></code> | `↦` |
/// | `arrow:l:r`        | `<->`     | `↔`    |
/// | `arrow:l:r:double` | `<=>`     | `⇔`    |
/// | `eq:not`           | `!=`      | `≠`    |
/// | `eq:gt`            | `>=`      | `≥`    |
/// | `eq:lt`            | `<=`      | `≤`    |
/// | `colon:eq`         | `:=`      | `≔`    |
///
/// ## Example
/// ```
/// // In text, with colons.
/// :arrow:l: \
/// :arrow:r: \
/// :arrow:t: \
/// :turtle: \
/// :face:halo: \
/// :woman:old:
///
/// // In math, directly.
/// $f : NN -> RR$ \
/// $A sub:eq B without C$ \
/// $a times:div b eq:not c$
/// ```
///
/// ## Parameters
/// - notation: EcoString (positional, required)
///   The symbol's symmie notation.
///
///   Consists of a name, followed by a number colon-separated modifiers
///   in no particular order.
///
///   ### Example
///   ```
///   #symbol("NN") \
///   #symbol("face:grin")
///   ```
///
/// ## Category
/// text
#[func]
#[capable(Show)]
#[derive(Debug, Hash)]
pub struct SymbolNode(pub EcoString);

#[node]
impl SymbolNode {
    fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
        Ok(Self(args.expect("notation")?).pack())
    }

    fn field(&self, name: &str) -> Option<Value> {
        match name {
            "notation" => Some(Value::Str(self.0.clone().into())),
            _ => None,
        }
    }
}

impl Show for SymbolNode {
    fn show(&self, _: &mut Vt, this: &Content, _: StyleChain) -> SourceResult<Content> {
        match symmie::get(&self.0) {
            Some(c) => Ok(TextNode::packed(c)),
            None => {
                if let Some(span) = this.span() {
                    bail!(span, "unknown symbol");
                }

                Ok(Content::empty())
            }
        }
    }
}
