use typst_syntax::Spanned;

use crate::diag::{LoadedWithin, SourceResult};
use crate::engine::Engine;
use crate::foundations::{Cast, PathOrStr, func};
use crate::loading::{DataSource, Load, Readable};

/// Reads plain text or data from a file.
///
/// By default, the file will be read as UTF-8 and returned as a @str[string].
///
/// If you specify `{encoding: none}`, this returns raw @bytes[bytes] instead.
///
/// = Example <example>
/// ```example
/// An example for a HTML file: \
/// #let text = read("example.html")
/// #raw(text, block: true, lang: "html")
///
/// Raw bytes:
/// #read("tiger.jpg", encoding: none)
/// ```
#[func]
pub fn read(
    engine: &mut Engine,
    /// Path to a file.
    path: Spanned<PathOrStr>,
    /// The encoding to read the file with.
    ///
    /// If set to `{none}`, this function returns raw bytes.
    #[named]
    #[default(Some(Encoding::Utf8))]
    encoding: Option<Encoding>,
) -> SourceResult<Readable> {
    let loaded = path.map(DataSource::Path).load(engine.world)?;
    Ok(match encoding {
        None => Readable::Bytes(loaded.data),
        Some(Encoding::Utf8) => Readable::Str(loaded.data.to_str().within(&loaded)?),
    })
}

/// An encoding of a file.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
pub enum Encoding {
    /// The Unicode UTF-8 encoding.
    Utf8,
}
