use std::fmt;
use std::io::{self, Write};

/// A JSON value that is either a number or a quoted string.
pub enum JsonVal<'a> {
    /// Integer value, serialised without quotes.
    Num(u64),
    /// String value, serialised with double quotes.
    Str(&'a str),
}

impl fmt::Display for JsonVal<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            JsonVal::Num(n) => write!(f, "{n}"),
            JsonVal::Str(s) => write!(f, "\"{s}\""),
        }
    }
}

/// Write a JSON object `{"k1":v1,"k2":v2,...}` to `writer`.
pub fn annotation<W: Write>(
    writer: &mut W,
    fields: &[(&str, JsonVal<'_>)],
) -> io::Result<()> {
    write!(writer, "{{")?;
    for (i, (k, v)) in fields.iter().enumerate() {
        if i > 0 {
            write!(writer, ",")?;
        }
        write!(writer, "\"{k}\":{v}")?;
    }
    write!(writer, "}}")
}

/// xxHash-64 of `ascii`, formatted as 16 uppercase hex digits.
pub fn seq_id(ascii: &[u8]) -> String {
    use xxhash_rust::xxh64::xxh64;
    format!("{:016X}", xxh64(ascii, 0))
}

/// Write `seq` as one line of ASCII DNA, followed by a newline.
pub fn write_sequence<W: Write>(writer: &mut W, seq: &[u8]) -> io::Result<()> {
    // SAFETY: seq is valid ASCII DNA (A/C/G/T).
    writeln!(writer, "{}", unsafe { std::str::from_utf8_unchecked(seq) })
}

/// Core FASTA record writer.
///
/// Writes `>{id} {annotation}\n{sequence}\n`.
pub fn write_record<W: Write>(
    seq: &[u8],
    id: &str,
    fields: &[(&str, JsonVal<'_>)],
    out: &mut W,
) -> io::Result<()> {
    write!(out, ">{id} ")?;
    annotation(out, fields)?;
    writeln!(out)?;
    write_sequence(out, seq)
}
