// codons.sy -- The universal genetic code as native Scyla.
//
// The standard genetic code maps every triplet of RNA nucleotides (codon)
// to one of 20 amino acids or a stop signal. There are 4^3 = 64 possible
// codons; 61 encode amino acids and 3 are stop codons. This module gives
// Scyla a compile-time lookup from any codon to its amino acid, and a
// translate() function that walks an mRNA string and produces the protein
// sequence as one-letter codes, stopping at the first stop codon.
//
// Codon → amino acid lookup is O(1). The function is total: any input of
// three valid RNA letters (A/U/G/C) returns exactly one result.
//
// The standard genetic code is nearly universal across all known life. Minor
// variants exist in mitochondrial genomes and some protozoa; this module
// implements the canonical (Standard Code, NCBI translation table 1).
//
// Sources:
//   - NCBI Genetic Codes, Translation Table 1 (Standard Code)
//   - Crick FHC, Barnett L, Brenner S, Watts-Tobin RJ. Nature 192:1227-1232, 1961
//   - Nirenberg M, Leder P. Science 145:1399-1407, 1964
//
// Marjorie McCubbins + Aether, April 2026
// Patent pending: 64/034,536 (continuation-in-part)

use amino_acids

// ═══════════════════════════════════════════════════════
// STRUCT
// ═══════════════════════════════════════════════════════

struct Codon {
    sequence: String,       // three-letter RNA codon, e.g. "AUG"
    amino_acid: String,     // one-letter code, or "*" for stop
    three_letter: String,   // "Met" for AUG, "***" for stop
    is_start: Bool,         // true for AUG (canonical start)
    is_stop: Bool,          // true for UAA, UAG, UGA
}

fn codon(s: String, aa: String, t: String, start: Bool, stop: Bool) -> Codon {
    return Codon { sequence: s, amino_acid: aa, three_letter: t, is_start: start, is_stop: stop }
}

fn unknown_codon(s: String) -> Codon {
    return codon(s, "X", "Xaa", false, false)
}

// ═══════════════════════════════════════════════════════
// THE STANDARD GENETIC CODE — 64 CODONS
// ═══════════════════════════════════════════════════════
//
// Lookup a codon by its RNA sequence. Codon input must be uppercase A/U/G/C.
// DNA input (with T instead of U) should be transcribed first.

fn lookup_codon(seq: String) -> Codon {
    // ─── Phenylalanine / Leucine (U first base) ───
    if seq == "UUU" { return codon("UUU", "F", "Phe", false, false) }
    if seq == "UUC" { return codon("UUC", "F", "Phe", false, false) }
    if seq == "UUA" { return codon("UUA", "L", "Leu", false, false) }
    if seq == "UUG" { return codon("UUG", "L", "Leu", false, false) }
    if seq == "CUU" { return codon("CUU", "L", "Leu", false, false) }
    if seq == "CUC" { return codon("CUC", "L", "Leu", false, false) }
    if seq == "CUA" { return codon("CUA", "L", "Leu", false, false) }
    if seq == "CUG" { return codon("CUG", "L", "Leu", false, false) }

    // ─── Isoleucine / Methionine (start) ───
    if seq == "AUU" { return codon("AUU", "I", "Ile", false, false) }
    if seq == "AUC" { return codon("AUC", "I", "Ile", false, false) }
    if seq == "AUA" { return codon("AUA", "I", "Ile", false, false) }
    if seq == "AUG" { return codon("AUG", "M", "Met", true,  false) }

    // ─── Valine ───
    if seq == "GUU" { return codon("GUU", "V", "Val", false, false) }
    if seq == "GUC" { return codon("GUC", "V", "Val", false, false) }
    if seq == "GUA" { return codon("GUA", "V", "Val", false, false) }
    if seq == "GUG" { return codon("GUG", "V", "Val", false, false) }

    // ─── Serine ───
    if seq == "UCU" { return codon("UCU", "S", "Ser", false, false) }
    if seq == "UCC" { return codon("UCC", "S", "Ser", false, false) }
    if seq == "UCA" { return codon("UCA", "S", "Ser", false, false) }
    if seq == "UCG" { return codon("UCG", "S", "Ser", false, false) }

    // ─── Proline ───
    if seq == "CCU" { return codon("CCU", "P", "Pro", false, false) }
    if seq == "CCC" { return codon("CCC", "P", "Pro", false, false) }
    if seq == "CCA" { return codon("CCA", "P", "Pro", false, false) }
    if seq == "CCG" { return codon("CCG", "P", "Pro", false, false) }

    // ─── Threonine ───
    if seq == "ACU" { return codon("ACU", "T", "Thr", false, false) }
    if seq == "ACC" { return codon("ACC", "T", "Thr", false, false) }
    if seq == "ACA" { return codon("ACA", "T", "Thr", false, false) }
    if seq == "ACG" { return codon("ACG", "T", "Thr", false, false) }

    // ─── Alanine ───
    if seq == "GCU" { return codon("GCU", "A", "Ala", false, false) }
    if seq == "GCC" { return codon("GCC", "A", "Ala", false, false) }
    if seq == "GCA" { return codon("GCA", "A", "Ala", false, false) }
    if seq == "GCG" { return codon("GCG", "A", "Ala", false, false) }

    // ─── Tyrosine / Stop ───
    if seq == "UAU" { return codon("UAU", "Y", "Tyr", false, false) }
    if seq == "UAC" { return codon("UAC", "Y", "Tyr", false, false) }
    if seq == "UAA" { return codon("UAA", "*", "***", false, true)  }
    if seq == "UAG" { return codon("UAG", "*", "***", false, true)  }

    // ─── Histidine / Glutamine ───
    if seq == "CAU" { return codon("CAU", "H", "His", false, false) }
    if seq == "CAC" { return codon("CAC", "H", "His", false, false) }
    if seq == "CAA" { return codon("CAA", "Q", "Gln", false, false) }
    if seq == "CAG" { return codon("CAG", "Q", "Gln", false, false) }

    // ─── Asparagine / Lysine ───
    if seq == "AAU" { return codon("AAU", "N", "Asn", false, false) }
    if seq == "AAC" { return codon("AAC", "N", "Asn", false, false) }
    if seq == "AAA" { return codon("AAA", "K", "Lys", false, false) }
    if seq == "AAG" { return codon("AAG", "K", "Lys", false, false) }

    // ─── Aspartate / Glutamate ───
    if seq == "GAU" { return codon("GAU", "D", "Asp", false, false) }
    if seq == "GAC" { return codon("GAC", "D", "Asp", false, false) }
    if seq == "GAA" { return codon("GAA", "E", "Glu", false, false) }
    if seq == "GAG" { return codon("GAG", "E", "Glu", false, false) }

    // ─── Cysteine / Stop / Tryptophan ───
    if seq == "UGU" { return codon("UGU", "C", "Cys", false, false) }
    if seq == "UGC" { return codon("UGC", "C", "Cys", false, false) }
    if seq == "UGA" { return codon("UGA", "*", "***", false, true)  }
    if seq == "UGG" { return codon("UGG", "W", "Trp", false, false) }

    // ─── Arginine ───
    if seq == "CGU" { return codon("CGU", "R", "Arg", false, false) }
    if seq == "CGC" { return codon("CGC", "R", "Arg", false, false) }
    if seq == "CGA" { return codon("CGA", "R", "Arg", false, false) }
    if seq == "CGG" { return codon("CGG", "R", "Arg", false, false) }

    // ─── Serine (AGU/AGC) / Arginine (AGA/AGG) ───
    if seq == "AGU" { return codon("AGU", "S", "Ser", false, false) }
    if seq == "AGC" { return codon("AGC", "S", "Ser", false, false) }
    if seq == "AGA" { return codon("AGA", "R", "Arg", false, false) }
    if seq == "AGG" { return codon("AGG", "R", "Arg", false, false) }

    // ─── Glycine ───
    if seq == "GGU" { return codon("GGU", "G", "Gly", false, false) }
    if seq == "GGC" { return codon("GGC", "G", "Gly", false, false) }
    if seq == "GGA" { return codon("GGA", "G", "Gly", false, false) }
    if seq == "GGG" { return codon("GGG", "G", "Gly", false, false) }

    return unknown_codon(seq)
}

// ═══════════════════════════════════════════════════════
// DNA → mRNA TRANSCRIPTION
// ═══════════════════════════════════════════════════════
//
// Transcription converts a DNA coding strand to mRNA by replacing T with U.
// (Biologically, RNA polymerase reads the template strand and produces an
// mRNA complementary to it — but the mRNA sequence is identical to the
// coding strand with T→U, so this one-character substitution captures it.)

fn transcribe_dna(dna: String) -> String {
    let result = ""
    let i = 0
    let n = str_len(dna)
    while i < n {
        let c = str_substring(dna, i, i + 1)
        if c == "T" { result = result + "U" }
        if c != "T" { result = result + c }
        i = i + 1
    }
    return result
}

// ═══════════════════════════════════════════════════════
// mRNA → PROTEIN TRANSLATION
// ═══════════════════════════════════════════════════════
//
// Walk the mRNA in frame, three nucleotides at a time, looking up each codon
// and appending its one-letter code to the growing protein sequence. Stop at
// the first stop codon. Translation begins at the first AUG (start codon).
// If no AUG is found, translation starts at position 0.

fn find_start(mrna: String) -> Int {
    let n = str_len(mrna)
    let i = 0
    while i + 3 <= n {
        let c = str_substring(mrna, i, i + 3)
        if c == "AUG" { return i }
        i = i + 1
    }
    return 0
}

fn translate(mrna: String) -> String {
    let start = find_start(mrna)
    let protein = ""
    let i = start
    let n = str_len(mrna)
    while i + 3 <= n {
        let triplet = str_substring(mrna, i, i + 3)
        let cd = lookup_codon(triplet)
        if cd.is_stop { return protein }
        protein = protein + cd.amino_acid
        i = i + 3
    }
    return protein
}

fn translate_from(mrna: String, frame_start: Int) -> String {
    let protein = ""
    let i = frame_start
    let n = str_len(mrna)
    while i + 3 <= n {
        let triplet = str_substring(mrna, i, i + 3)
        let cd = lookup_codon(triplet)
        if cd.is_stop { return protein }
        protein = protein + cd.amino_acid
        i = i + 3
    }
    return protein
}

// ═══════════════════════════════════════════════════════
// QUICK-ACCESS HELPERS
// ═══════════════════════════════════════════════════════

fn codon_count() -> Int {
    return 64
}

fn stop_codon_count() -> Int {
    return 3
}

fn coding_codon_count() -> Int {
    return 61
}
