// periodic.sy -- The complete periodic table as native Scyla.
//
// All 118 elements with their IUPAC 2023 standard properties:
//   atomic_number, symbol, name, atomic_mass (g/mol),
//   electronegativity (Pauling scale, -1.0 if not applicable),
//   group (1-18, or 0 for lanthanides/actinides), period (1-7),
//   block (s/p/d/f), category (alkali metal, halogen, noble gas, etc.)
//
// This module turns chemistry into first-class Scyla data. A pharmaceutical
// molecule's molecular weight can be computed from its atoms with no external
// library calls. Drug interactions can reason over electronegativity, group,
// and period. Wet-lab protocols can validate reagents against their
// published atomic masses with zero round-trip to Wikipedia.
//
// Sources:
//   - IUPAC 2023 Standard Atomic Weights
//   - NIST Atomic Weights and Isotopic Compositions Database
//   - Pauling electronegativity scale (Pauling 1932, rev. Allred & Rochow 1958)
//
// Marjorie McCubbins + Aether, April 2026
// Patent pending: 64/034,536 (continuation-in-part)

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

struct Element {
    atomic_number: Int,
    symbol: String,
    name: String,
    atomic_mass: Float,
    electronegativity: Float,
    group: Int,
    period: Int,
    block: String,
    category: String,
}

fn element(n: Int, sym: String, nm: String, m: Float, en: Float, g: Int, p: Int, b: String, c: String) -> Element {
    return Element { atomic_number: n, symbol: sym, name: nm, atomic_mass: m, electronegativity: en, group: g, period: p, block: b, category: c }
}

fn unknown_element() -> Element {
    return element(0, "UNK", "Unknown", 0.0, -1.0, 0, 0, "", "")
}

// ═══════════════════════════════════════════════════════
// LOOKUP BY ATOMIC NUMBER (1 - 118)
// ═══════════════════════════════════════════════════════

fn lookup_element(z: Int) -> Element {
    // ─── Period 1 ─────────────────────────────────────
    if z == 1 { return element(1, "H", "Hydrogen", 1.008, 2.20, 1, 1, "s", "nonmetal") }
    if z == 2 { return element(2, "He", "Helium", 4.0026, -1.0, 18, 1, "s", "noble gas") }

    // ─── Period 2 ─────────────────────────────────────
    if z == 3 { return element(3, "Li", "Lithium", 6.94, 0.98, 1, 2, "s", "alkali metal") }
    if z == 4 { return element(4, "Be", "Beryllium", 9.0122, 1.57, 2, 2, "s", "alkaline earth metal") }
    if z == 5 { return element(5, "B", "Boron", 10.81, 2.04, 13, 2, "p", "metalloid") }
    if z == 6 { return element(6, "C", "Carbon", 12.011, 2.55, 14, 2, "p", "nonmetal") }
    if z == 7 { return element(7, "N", "Nitrogen", 14.007, 3.04, 15, 2, "p", "nonmetal") }
    if z == 8 { return element(8, "O", "Oxygen", 15.999, 3.44, 16, 2, "p", "nonmetal") }
    if z == 9 { return element(9, "F", "Fluorine", 18.998, 3.98, 17, 2, "p", "halogen") }
    if z == 10 { return element(10, "Ne", "Neon", 20.180, -1.0, 18, 2, "p", "noble gas") }

    // ─── Period 3 ─────────────────────────────────────
    if z == 11 { return element(11, "Na", "Sodium", 22.990, 0.93, 1, 3, "s", "alkali metal") }
    if z == 12 { return element(12, "Mg", "Magnesium", 24.305, 1.31, 2, 3, "s", "alkaline earth metal") }
    if z == 13 { return element(13, "Al", "Aluminum", 26.982, 1.61, 13, 3, "p", "post-transition metal") }
    if z == 14 { return element(14, "Si", "Silicon", 28.085, 1.90, 14, 3, "p", "metalloid") }
    if z == 15 { return element(15, "P", "Phosphorus", 30.974, 2.19, 15, 3, "p", "nonmetal") }
    if z == 16 { return element(16, "S", "Sulfur", 32.06, 2.58, 16, 3, "p", "nonmetal") }
    if z == 17 { return element(17, "Cl", "Chlorine", 35.45, 3.16, 17, 3, "p", "halogen") }
    if z == 18 { return element(18, "Ar", "Argon", 39.948, -1.0, 18, 3, "p", "noble gas") }

    // ─── Period 4 ─────────────────────────────────────
    if z == 19 { return element(19, "K", "Potassium", 39.098, 0.82, 1, 4, "s", "alkali metal") }
    if z == 20 { return element(20, "Ca", "Calcium", 40.078, 1.00, 2, 4, "s", "alkaline earth metal") }
    if z == 21 { return element(21, "Sc", "Scandium", 44.956, 1.36, 3, 4, "d", "transition metal") }
    if z == 22 { return element(22, "Ti", "Titanium", 47.867, 1.54, 4, 4, "d", "transition metal") }
    if z == 23 { return element(23, "V", "Vanadium", 50.942, 1.63, 5, 4, "d", "transition metal") }
    if z == 24 { return element(24, "Cr", "Chromium", 51.996, 1.66, 6, 4, "d", "transition metal") }
    if z == 25 { return element(25, "Mn", "Manganese", 54.938, 1.55, 7, 4, "d", "transition metal") }
    if z == 26 { return element(26, "Fe", "Iron", 55.845, 1.83, 8, 4, "d", "transition metal") }
    if z == 27 { return element(27, "Co", "Cobalt", 58.933, 1.88, 9, 4, "d", "transition metal") }
    if z == 28 { return element(28, "Ni", "Nickel", 58.693, 1.91, 10, 4, "d", "transition metal") }
    if z == 29 { return element(29, "Cu", "Copper", 63.546, 1.90, 11, 4, "d", "transition metal") }
    if z == 30 { return element(30, "Zn", "Zinc", 65.38, 1.65, 12, 4, "d", "transition metal") }
    if z == 31 { return element(31, "Ga", "Gallium", 69.723, 1.81, 13, 4, "p", "post-transition metal") }
    if z == 32 { return element(32, "Ge", "Germanium", 72.630, 2.01, 14, 4, "p", "metalloid") }
    if z == 33 { return element(33, "As", "Arsenic", 74.922, 2.18, 15, 4, "p", "metalloid") }
    if z == 34 { return element(34, "Se", "Selenium", 78.971, 2.55, 16, 4, "p", "nonmetal") }
    if z == 35 { return element(35, "Br", "Bromine", 79.904, 2.96, 17, 4, "p", "halogen") }
    if z == 36 { return element(36, "Kr", "Krypton", 83.798, 3.00, 18, 4, "p", "noble gas") }

    // ─── Period 5 ─────────────────────────────────────
    if z == 37 { return element(37, "Rb", "Rubidium", 85.468, 0.82, 1, 5, "s", "alkali metal") }
    if z == 38 { return element(38, "Sr", "Strontium", 87.62, 0.95, 2, 5, "s", "alkaline earth metal") }
    if z == 39 { return element(39, "Y", "Yttrium", 88.906, 1.22, 3, 5, "d", "transition metal") }
    if z == 40 { return element(40, "Zr", "Zirconium", 91.224, 1.33, 4, 5, "d", "transition metal") }
    if z == 41 { return element(41, "Nb", "Niobium", 92.906, 1.6, 5, 5, "d", "transition metal") }
    if z == 42 { return element(42, "Mo", "Molybdenum", 95.95, 2.16, 6, 5, "d", "transition metal") }
    if z == 43 { return element(43, "Tc", "Technetium", 98.0, 1.9, 7, 5, "d", "transition metal") }
    if z == 44 { return element(44, "Ru", "Ruthenium", 101.07, 2.2, 8, 5, "d", "transition metal") }
    if z == 45 { return element(45, "Rh", "Rhodium", 102.91, 2.28, 9, 5, "d", "transition metal") }
    if z == 46 { return element(46, "Pd", "Palladium", 106.42, 2.20, 10, 5, "d", "transition metal") }
    if z == 47 { return element(47, "Ag", "Silver", 107.87, 1.93, 11, 5, "d", "transition metal") }
    if z == 48 { return element(48, "Cd", "Cadmium", 112.41, 1.69, 12, 5, "d", "transition metal") }
    if z == 49 { return element(49, "In", "Indium", 114.82, 1.78, 13, 5, "p", "post-transition metal") }
    if z == 50 { return element(50, "Sn", "Tin", 118.71, 1.96, 14, 5, "p", "post-transition metal") }
    if z == 51 { return element(51, "Sb", "Antimony", 121.76, 2.05, 15, 5, "p", "metalloid") }
    if z == 52 { return element(52, "Te", "Tellurium", 127.60, 2.1, 16, 5, "p", "metalloid") }
    if z == 53 { return element(53, "I", "Iodine", 126.90, 2.66, 17, 5, "p", "halogen") }
    if z == 54 { return element(54, "Xe", "Xenon", 131.29, 2.6, 18, 5, "p", "noble gas") }

    // ─── Period 6 ─────────────────────────────────────
    if z == 55 { return element(55, "Cs", "Cesium", 132.91, 0.79, 1, 6, "s", "alkali metal") }
    if z == 56 { return element(56, "Ba", "Barium", 137.33, 0.89, 2, 6, "s", "alkaline earth metal") }
    if z == 57 { return element(57, "La", "Lanthanum", 138.91, 1.10, 0, 6, "f", "lanthanide") }
    if z == 58 { return element(58, "Ce", "Cerium", 140.12, 1.12, 0, 6, "f", "lanthanide") }
    if z == 59 { return element(59, "Pr", "Praseodymium", 140.91, 1.13, 0, 6, "f", "lanthanide") }
    if z == 60 { return element(60, "Nd", "Neodymium", 144.24, 1.14, 0, 6, "f", "lanthanide") }
    if z == 61 { return element(61, "Pm", "Promethium", 145.0, 1.13, 0, 6, "f", "lanthanide") }
    if z == 62 { return element(62, "Sm", "Samarium", 150.36, 1.17, 0, 6, "f", "lanthanide") }
    if z == 63 { return element(63, "Eu", "Europium", 151.96, 1.2, 0, 6, "f", "lanthanide") }
    if z == 64 { return element(64, "Gd", "Gadolinium", 157.25, 1.20, 0, 6, "f", "lanthanide") }
    if z == 65 { return element(65, "Tb", "Terbium", 158.93, 1.10, 0, 6, "f", "lanthanide") }
    if z == 66 { return element(66, "Dy", "Dysprosium", 162.50, 1.22, 0, 6, "f", "lanthanide") }
    if z == 67 { return element(67, "Ho", "Holmium", 164.93, 1.23, 0, 6, "f", "lanthanide") }
    if z == 68 { return element(68, "Er", "Erbium", 167.26, 1.24, 0, 6, "f", "lanthanide") }
    if z == 69 { return element(69, "Tm", "Thulium", 168.93, 1.25, 0, 6, "f", "lanthanide") }
    if z == 70 { return element(70, "Yb", "Ytterbium", 173.05, 1.1, 0, 6, "f", "lanthanide") }
    if z == 71 { return element(71, "Lu", "Lutetium", 174.97, 1.27, 3, 6, "d", "lanthanide") }
    if z == 72 { return element(72, "Hf", "Hafnium", 178.49, 1.3, 4, 6, "d", "transition metal") }
    if z == 73 { return element(73, "Ta", "Tantalum", 180.95, 1.5, 5, 6, "d", "transition metal") }
    if z == 74 { return element(74, "W", "Tungsten", 183.84, 2.36, 6, 6, "d", "transition metal") }
    if z == 75 { return element(75, "Re", "Rhenium", 186.21, 1.9, 7, 6, "d", "transition metal") }
    if z == 76 { return element(76, "Os", "Osmium", 190.23, 2.2, 8, 6, "d", "transition metal") }
    if z == 77 { return element(77, "Ir", "Iridium", 192.22, 2.20, 9, 6, "d", "transition metal") }
    if z == 78 { return element(78, "Pt", "Platinum", 195.08, 2.28, 10, 6, "d", "transition metal") }
    if z == 79 { return element(79, "Au", "Gold", 196.97, 2.54, 11, 6, "d", "transition metal") }
    if z == 80 { return element(80, "Hg", "Mercury", 200.59, 2.00, 12, 6, "d", "post-transition metal") }
    if z == 81 { return element(81, "Tl", "Thallium", 204.38, 1.62, 13, 6, "p", "post-transition metal") }
    if z == 82 { return element(82, "Pb", "Lead", 207.2, 2.33, 14, 6, "p", "post-transition metal") }
    if z == 83 { return element(83, "Bi", "Bismuth", 208.98, 2.02, 15, 6, "p", "post-transition metal") }
    if z == 84 { return element(84, "Po", "Polonium", 209.0, 2.0, 16, 6, "p", "metalloid") }
    if z == 85 { return element(85, "At", "Astatine", 210.0, 2.2, 17, 6, "p", "halogen") }
    if z == 86 { return element(86, "Rn", "Radon", 222.0, -1.0, 18, 6, "p", "noble gas") }

    // ─── Period 7 ─────────────────────────────────────
    if z == 87 { return element(87, "Fr", "Francium", 223.0, 0.7, 1, 7, "s", "alkali metal") }
    if z == 88 { return element(88, "Ra", "Radium", 226.0, 0.9, 2, 7, "s", "alkaline earth metal") }
    if z == 89 { return element(89, "Ac", "Actinium", 227.0, 1.1, 0, 7, "f", "actinide") }
    if z == 90 { return element(90, "Th", "Thorium", 232.04, 1.3, 0, 7, "f", "actinide") }
    if z == 91 { return element(91, "Pa", "Protactinium", 231.04, 1.5, 0, 7, "f", "actinide") }
    if z == 92 { return element(92, "U", "Uranium", 238.03, 1.38, 0, 7, "f", "actinide") }
    if z == 93 { return element(93, "Np", "Neptunium", 237.0, 1.36, 0, 7, "f", "actinide") }
    if z == 94 { return element(94, "Pu", "Plutonium", 244.0, 1.28, 0, 7, "f", "actinide") }
    if z == 95 { return element(95, "Am", "Americium", 243.0, 1.13, 0, 7, "f", "actinide") }
    if z == 96 { return element(96, "Cm", "Curium", 247.0, 1.28, 0, 7, "f", "actinide") }
    if z == 97 { return element(97, "Bk", "Berkelium", 247.0, 1.3, 0, 7, "f", "actinide") }
    if z == 98 { return element(98, "Cf", "Californium", 251.0, 1.3, 0, 7, "f", "actinide") }
    if z == 99 { return element(99, "Es", "Einsteinium", 252.0, 1.3, 0, 7, "f", "actinide") }
    if z == 100 { return element(100, "Fm", "Fermium", 257.0, 1.3, 0, 7, "f", "actinide") }
    if z == 101 { return element(101, "Md", "Mendelevium", 258.0, 1.3, 0, 7, "f", "actinide") }
    if z == 102 { return element(102, "No", "Nobelium", 259.0, 1.3, 0, 7, "f", "actinide") }
    if z == 103 { return element(103, "Lr", "Lawrencium", 266.0, 1.3, 3, 7, "d", "actinide") }
    if z == 104 { return element(104, "Rf", "Rutherfordium", 267.0, -1.0, 4, 7, "d", "transition metal") }
    if z == 105 { return element(105, "Db", "Dubnium", 268.0, -1.0, 5, 7, "d", "transition metal") }
    if z == 106 { return element(106, "Sg", "Seaborgium", 269.0, -1.0, 6, 7, "d", "transition metal") }
    if z == 107 { return element(107, "Bh", "Bohrium", 270.0, -1.0, 7, 7, "d", "transition metal") }
    if z == 108 { return element(108, "Hs", "Hassium", 277.0, -1.0, 8, 7, "d", "transition metal") }
    if z == 109 { return element(109, "Mt", "Meitnerium", 278.0, -1.0, 9, 7, "d", "transition metal") }
    if z == 110 { return element(110, "Ds", "Darmstadtium", 281.0, -1.0, 10, 7, "d", "transition metal") }
    if z == 111 { return element(111, "Rg", "Roentgenium", 282.0, -1.0, 11, 7, "d", "transition metal") }
    if z == 112 { return element(112, "Cn", "Copernicium", 285.0, -1.0, 12, 7, "d", "transition metal") }
    if z == 113 { return element(113, "Nh", "Nihonium", 286.0, -1.0, 13, 7, "p", "post-transition metal") }
    if z == 114 { return element(114, "Fl", "Flerovium", 289.0, -1.0, 14, 7, "p", "post-transition metal") }
    if z == 115 { return element(115, "Mc", "Moscovium", 290.0, -1.0, 15, 7, "p", "post-transition metal") }
    if z == 116 { return element(116, "Lv", "Livermorium", 293.0, -1.0, 16, 7, "p", "post-transition metal") }
    if z == 117 { return element(117, "Ts", "Tennessine", 294.0, -1.0, 17, 7, "p", "halogen") }
    if z == 118 { return element(118, "Og", "Oganesson", 294.0, -1.0, 18, 7, "p", "noble gas") }

    return unknown_element()
}

// ═══════════════════════════════════════════════════════
// LOOKUP BY SYMBOL (case-sensitive, e.g. "Fe" not "FE")
// ═══════════════════════════════════════════════════════
//
// The compiler's type-aware string equality (fixed April 2026) makes this
// a simple dispatch. Symbol → atomic number → lookup_element.

fn element_by_symbol(sym: String) -> Element {
    if sym == "H"  { return lookup_element(1) }
    if sym == "He" { return lookup_element(2) }
    if sym == "Li" { return lookup_element(3) }
    if sym == "Be" { return lookup_element(4) }
    if sym == "B"  { return lookup_element(5) }
    if sym == "C"  { return lookup_element(6) }
    if sym == "N"  { return lookup_element(7) }
    if sym == "O"  { return lookup_element(8) }
    if sym == "F"  { return lookup_element(9) }
    if sym == "Ne" { return lookup_element(10) }
    if sym == "Na" { return lookup_element(11) }
    if sym == "Mg" { return lookup_element(12) }
    if sym == "Al" { return lookup_element(13) }
    if sym == "Si" { return lookup_element(14) }
    if sym == "P"  { return lookup_element(15) }
    if sym == "S"  { return lookup_element(16) }
    if sym == "Cl" { return lookup_element(17) }
    if sym == "Ar" { return lookup_element(18) }
    if sym == "K"  { return lookup_element(19) }
    if sym == "Ca" { return lookup_element(20) }
    if sym == "Sc" { return lookup_element(21) }
    if sym == "Ti" { return lookup_element(22) }
    if sym == "V"  { return lookup_element(23) }
    if sym == "Cr" { return lookup_element(24) }
    if sym == "Mn" { return lookup_element(25) }
    if sym == "Fe" { return lookup_element(26) }
    if sym == "Co" { return lookup_element(27) }
    if sym == "Ni" { return lookup_element(28) }
    if sym == "Cu" { return lookup_element(29) }
    if sym == "Zn" { return lookup_element(30) }
    if sym == "Ga" { return lookup_element(31) }
    if sym == "Ge" { return lookup_element(32) }
    if sym == "As" { return lookup_element(33) }
    if sym == "Se" { return lookup_element(34) }
    if sym == "Br" { return lookup_element(35) }
    if sym == "Kr" { return lookup_element(36) }
    if sym == "Rb" { return lookup_element(37) }
    if sym == "Sr" { return lookup_element(38) }
    if sym == "Y"  { return lookup_element(39) }
    if sym == "Zr" { return lookup_element(40) }
    if sym == "Nb" { return lookup_element(41) }
    if sym == "Mo" { return lookup_element(42) }
    if sym == "Tc" { return lookup_element(43) }
    if sym == "Ru" { return lookup_element(44) }
    if sym == "Rh" { return lookup_element(45) }
    if sym == "Pd" { return lookup_element(46) }
    if sym == "Ag" { return lookup_element(47) }
    if sym == "Cd" { return lookup_element(48) }
    if sym == "In" { return lookup_element(49) }
    if sym == "Sn" { return lookup_element(50) }
    if sym == "Sb" { return lookup_element(51) }
    if sym == "Te" { return lookup_element(52) }
    if sym == "I"  { return lookup_element(53) }
    if sym == "Xe" { return lookup_element(54) }
    if sym == "Cs" { return lookup_element(55) }
    if sym == "Ba" { return lookup_element(56) }
    if sym == "La" { return lookup_element(57) }
    if sym == "Ce" { return lookup_element(58) }
    if sym == "Pr" { return lookup_element(59) }
    if sym == "Nd" { return lookup_element(60) }
    if sym == "Pm" { return lookup_element(61) }
    if sym == "Sm" { return lookup_element(62) }
    if sym == "Eu" { return lookup_element(63) }
    if sym == "Gd" { return lookup_element(64) }
    if sym == "Tb" { return lookup_element(65) }
    if sym == "Dy" { return lookup_element(66) }
    if sym == "Ho" { return lookup_element(67) }
    if sym == "Er" { return lookup_element(68) }
    if sym == "Tm" { return lookup_element(69) }
    if sym == "Yb" { return lookup_element(70) }
    if sym == "Lu" { return lookup_element(71) }
    if sym == "Hf" { return lookup_element(72) }
    if sym == "Ta" { return lookup_element(73) }
    if sym == "W"  { return lookup_element(74) }
    if sym == "Re" { return lookup_element(75) }
    if sym == "Os" { return lookup_element(76) }
    if sym == "Ir" { return lookup_element(77) }
    if sym == "Pt" { return lookup_element(78) }
    if sym == "Au" { return lookup_element(79) }
    if sym == "Hg" { return lookup_element(80) }
    if sym == "Tl" { return lookup_element(81) }
    if sym == "Pb" { return lookup_element(82) }
    if sym == "Bi" { return lookup_element(83) }
    if sym == "Po" { return lookup_element(84) }
    if sym == "At" { return lookup_element(85) }
    if sym == "Rn" { return lookup_element(86) }
    if sym == "Fr" { return lookup_element(87) }
    if sym == "Ra" { return lookup_element(88) }
    if sym == "Ac" { return lookup_element(89) }
    if sym == "Th" { return lookup_element(90) }
    if sym == "Pa" { return lookup_element(91) }
    if sym == "U"  { return lookup_element(92) }
    if sym == "Np" { return lookup_element(93) }
    if sym == "Pu" { return lookup_element(94) }
    if sym == "Am" { return lookup_element(95) }
    if sym == "Cm" { return lookup_element(96) }
    if sym == "Bk" { return lookup_element(97) }
    if sym == "Cf" { return lookup_element(98) }
    if sym == "Es" { return lookup_element(99) }
    if sym == "Fm" { return lookup_element(100) }
    if sym == "Md" { return lookup_element(101) }
    if sym == "No" { return lookup_element(102) }
    if sym == "Lr" { return lookup_element(103) }
    if sym == "Rf" { return lookup_element(104) }
    if sym == "Db" { return lookup_element(105) }
    if sym == "Sg" { return lookup_element(106) }
    if sym == "Bh" { return lookup_element(107) }
    if sym == "Hs" { return lookup_element(108) }
    if sym == "Mt" { return lookup_element(109) }
    if sym == "Ds" { return lookup_element(110) }
    if sym == "Rg" { return lookup_element(111) }
    if sym == "Cn" { return lookup_element(112) }
    if sym == "Nh" { return lookup_element(113) }
    if sym == "Fl" { return lookup_element(114) }
    if sym == "Mc" { return lookup_element(115) }
    if sym == "Lv" { return lookup_element(116) }
    if sym == "Ts" { return lookup_element(117) }
    if sym == "Og" { return lookup_element(118) }
    return unknown_element()
}

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

fn atomic_mass(sym: String) -> Float {
    return element_by_symbol(sym).atomic_mass
}

fn electronegativity(sym: String) -> Float {
    return element_by_symbol(sym).electronegativity
}

fn element_count() -> Int {
    return 118
}

fn is_valid_atomic_number(z: Int) -> Bool {
    return z >= 1 and z <= 118
}
