# Nexus Membrane: Virtual Terminal Emulator
import term_font
import ion_client

const TERM_COLS* = 100
const TERM_ROWS* = 37

# Sovereign Palette (Phased Aesthetics)
const
  COLOR_SOVEREIGN_BLUE = 0xFF401010'u32
  COLOR_PHOSPHOR_AMBER = 0xFF00B0FF'u32
  COLOR_SCANLINE_DIM = 0xFF300808'u32

type
  Cell = object
    ch: char
    fg: uint32
    bg: uint32
    dirty: bool

var grid: array[TERM_ROWS, array[TERM_COLS, Cell]]
var cursor_x, cursor_y: int
var color_fg: uint32 = COLOR_PHOSPHOR_AMBER
var color_bg: uint32 = COLOR_SOVEREIGN_BLUE
var term_dirty*: bool = true

var fb_ptr: ptr UncheckedArray[uint32]
var fb_w, fb_h, fb_stride: int

# ANSI State Machine
type AnsiState = enum
  Normal, Escape, CSI, Param

var cur_state: AnsiState = Normal
var ansi_params: array[8, int]
var cur_param_idx: int

const PALETTE: array[16, uint32] = [
  0xFF000000'u32, # 0: Black
  0xFF0000AA'u32, # 1: Red
  0xFF00AA00'u32, # 2: Green
  0xFF00AAAA'u32, # 3: Brown/Yellow
  0xFFAA0000'u32, # 4: Blue
  0xFFAA00AA'u32, # 5: Magenta
  0xFFAAAA00'u32, # 6: Cyan
  0xFFAAAAAA'u32, # 7: Gray
  0xFF555555'u32, # 8: Bright Black
  0xFF5555FF'u32, # 9: Bright Red
  0xFF55FF55'u32, # 10: Bright Green
  0xFF55FFFF'u32, # 11: Bright Yellow
  0xFFFF5555'u32, # 12: Bright Blue
  0xFFFF55FF'u32, # 13: Bright Magenta
  0xFFFFFF55'u32, # 14: Bright Cyan
  0xFFFFFFFF'u32  # 15: White
]

proc handle_sgr() =
  ## Handle Select Graphic Rendition (m)
  if cur_param_idx == 0: # reset
    color_fg = COLOR_PHOSPHOR_AMBER
    color_bg = COLOR_SOVEREIGN_BLUE
    return

  for i in 0..<cur_param_idx:
    let p = ansi_params[i]
    if p == 0:
      color_fg = COLOR_PHOSPHOR_AMBER
      color_bg = COLOR_SOVEREIGN_BLUE
    elif p >= 30 and p <= 37:
      color_fg = PALETTE[p - 30]
    elif p >= 40 and p <= 47:
      color_bg = PALETTE[p - 40]
    elif p >= 90 and p <= 97:
      color_fg = PALETTE[p - 90 + 8]
    elif p >= 100 and p <= 107:
      color_bg = PALETTE[p - 100 + 8]


proc term_clear*() =
  for row in 0..<TERM_ROWS:
    for col in 0..<TERM_COLS:
      grid[row][col] = Cell(ch: ' ', fg: color_fg, bg: color_bg, dirty: true)
  cursor_x = 0
  cursor_y = 0
  cur_state = Normal
  term_dirty = true

proc term_scroll() =
  for row in 0..<(TERM_ROWS-1):
    grid[row] = grid[row + 1]
    for col in 0..<TERM_COLS: grid[row][col].dirty = true
  for col in 0..<TERM_COLS:
    grid[TERM_ROWS-1][col] = Cell(ch: ' ', fg: color_fg, bg: color_bg, dirty: true)
  term_dirty = true

proc term_putc*(ch: char) =
  case cur_state
  of Normal:
    if ch == '\x1b':
      cur_state = Escape
      return
    
    if ch == '\n':
      cursor_x = 0
      cursor_y += 1
    elif ch == '\r':
      cursor_x = 0
    elif ch >= ' ':
      if cursor_x >= TERM_COLS:
        cursor_x = 0
        cursor_y += 1
      if cursor_y >= TERM_ROWS:
        term_scroll()
        cursor_y = TERM_ROWS - 1
      grid[cursor_y][cursor_x] = Cell(ch: ch, fg: color_fg, bg: color_bg, dirty: true)
      cursor_x += 1
      term_dirty = true

  of Escape:
    if ch == '[':
      cur_state = CSI
      cur_param_idx = 0
      for i in 0..<ansi_params.len: ansi_params[i] = 0
    else:
      cur_state = Normal

  of CSI:
    if ch >= '0' and ch <= '9':
      ansi_params[cur_param_idx] = (ch.int - '0'.int)
      cur_state = Param
    elif ch == ';':
      if cur_param_idx < ansi_params.len - 1: cur_param_idx += 1
    elif ch == 'm':
      if cur_state == Param or cur_param_idx > 0 or ch == 'm': # Handle single m or param m
        if cur_state == Param: cur_param_idx += 1
        handle_sgr()
      cur_state = Normal
    elif ch == 'H' or ch == 'f': # Cursor Home
      cursor_x = 0; cursor_y = 0
      cur_state = Normal
    elif ch == 'J': # Clear Screen
      term_clear()
      cur_state = Normal
    else:
      cur_state = Normal

  of Param:
    if ch >= '0' and ch <= '9':
      ansi_params[cur_param_idx] = ansi_params[cur_param_idx] * 10 + (ch.int - '0'.int)
    elif ch == ';':
      if cur_param_idx < ansi_params.len - 1: cur_param_idx += 1
    elif ch == 'm':
      cur_param_idx += 1
      handle_sgr()
      cur_state = Normal
    elif ch == 'H' or ch == 'f':
      # pos logic here if we wanted it
      cursor_x = 0; cursor_y = 0
      cur_state = Normal
    else:
      cur_state = Normal

# --- THE GHOST RENDERER ---
proc draw_char(cx, cy: int, cell: Cell) =
  if fb_ptr == nil: return

  let glyph_idx = uint8(cell.ch)
  let fg = cell.fg
  let bg = cell.bg
  let px_start = cx * 8
  let py_start = cy * 16

  for y in 0..15:
    let is_scanline = (y mod 4) == 3
    let row_bits = FONT_BITMAP[glyph_idx][y]
    let screen_y = py_start + y
    if screen_y >= fb_h: break

    let row_offset = screen_y * (fb_stride div 4)
    for x in 0..7:
      let screen_x = px_start + x
      if screen_x >= fb_w: break
      let pixel_idx = row_offset + screen_x
      let is_pixel = ((int(row_bits) shr (7 - x)) and 1) != 0

      if is_pixel:
        fb_ptr[pixel_idx] = if is_scanline: (fg and 0xFFE0E0E0'u32) else: fg
      else:
        fb_ptr[pixel_idx] = if is_scanline: COLOR_SCANLINE_DIM else: bg

proc term_render*() =
  if fb_ptr == nil or not term_dirty: return
  for row in 0..<TERM_ROWS:
    for col in 0..<TERM_COLS:
      if grid[row][col].dirty:
        draw_char(col, row, grid[row][col])
        grid[row][col].dirty = false
  term_dirty = false

proc term_init*() =
  let sys = cast[ptr SysTable](SYS_TABLE_ADDR)
  fb_ptr = cast[ptr UncheckedArray[uint32]](sys.fb_addr)
  fb_w = int(sys.fb_width)
  fb_h = int(sys.fb_height)
  fb_stride = int(sys.fb_stride)
  cursor_x = 0
  cursor_y = 0
  cur_state = Normal
  term_dirty = true

  when defined(TERM_PROFILE_minimal):
    proc console_write(p: pointer, len: uint) {.importc, cdecl.}
    var msg = "[TERM] Profile: MINIMAL (IBM VGA/Hack)\n"
    console_write(addr msg[0], uint(msg.len))
  elif defined(TERM_PROFILE_standard):
    proc console_write(p: pointer, len: uint) {.importc, cdecl.}
    var msg = "[TERM] Profile: STANDARD (Spleen/Nerd)\n"
    console_write(addr msg[0], uint(msg.len))
  
  for row in 0..<TERM_ROWS:
    for col in 0..<TERM_COLS:
      grid[row][col] = Cell(ch: ' ', fg: color_fg, bg: color_bg, dirty: true)

  # Test Colors
  let test_msg = "\x1b[31mN\x1b[32mE\x1b[33mX\x1b[34mU\x1b[35mS\x1b[0m\n"
  for ch in test_msg: term_putc(ch)
