// Tapestry letter grammar — frozen once shipped. Mirror of the server's
// `app/Halflight/Support/TapestryGrammar.php`. The two files must match
// byte for byte: every letter that ships is a public commitment, and new
// meanings claim new letters rather than reassign existing ones.
//
// Mnemonic, not sequential. Case carries valence:
//   uppercase = creative / affirming / active
//   lowercase = passive / consumptive / corrective

export const TAPESTRY_LETTERS = {
  // Authored
  P: 'new post',
  C: 'comment',
  M: 'media/caption edit',
  V: 'rsvp',
  // Social affirm
  L: 'like',
  R: 'reblog',
  B: 'bookmark',
  F: 'follow',
  // Communication
  D: 'dm sent',
  N: 'notification read',
  // Admin
  E: 'edit profile',
  T: 'theme change',
  // Consumption (lowercase)
  s: 'scroll segment',
  v: 'open post detail',
  e: 'explore tap',
  // Corrective (lowercase)
  u: 'unfollow / unlike',
  d: 'delete own post',
  x: 'report',
  // Reserved: server's TapestryGrammar.php keeps `n` (Updates-tab focus)
  // out of the alphabet pending a coordinated client+server commit.
} as const

export type Letter = keyof typeof TAPESTRY_LETTERS

export const MAX_BODY_BYTES = 256

const ALPHABET: ReadonlySet<string> = new Set(Object.keys(TAPESTRY_LETTERS))

export function isLetter(byte: string): byte is Letter {
  return byte.length === 1 && ALPHABET.has(byte)
}

export function isValidBody(body: string): boolean {
  if (body.length === 0 || body.length > MAX_BODY_BYTES) return false
  for (let i = 0; i < body.length; i++) {
    if (!ALPHABET.has(body[i]!)) return false
  }
  return true
}
