import type { App } from '$apps'
import { TOES_URL } from '$apps'

const RENDER_DEBOUNCE = 50

let _apps: App[] = []
let _enabled = (process.stdout.isTTY ?? false) && !process.env.DEBUG
let _lastRender = 0
let _renderTimer: Timer | undefined
let _hostLogListeners = new Set<(text: string) => void>()
let _showEmoji = false

export const onHostLog = (cb: (text: string) => void) => {
  _hostLogListeners.add(cb)
}

export const setShowEmoji = (show: boolean) => {
  _showEmoji = show
  scheduleRender()
}

export function appLog(app: App, ...msg: string[]) {
  if (!_enabled) {
    console.log('🐾', `[${app.name}]`, msg.join(' '))
  }
}

export function hostLog(...msg: string[]) {
  const text = msg.join(' ')
  if (!_enabled) console.log('🐾', text)
  for (const listener of _hostLogListeners) listener(text)
}

export function setApps(apps: App[]) {
  _apps = apps
  scheduleRender()
}

const formatStatus = (app: App): string => {
  switch (app.state) {
    case 'running':
      return '\x1b[32m●\x1b[0m'
    case 'starting':
      return '\x1b[33m◐\x1b[0m'
    case 'stopping':
      return '\x1b[33m◑\x1b[0m'
    case 'stopped':
      return '\x1b[90m○\x1b[0m'
    case 'invalid':
      return '\x1b[31m✕\x1b[0m'
    default:
      return '\x1b[90m?\x1b[0m'
  }
}

const formatAppLine = (app: App, indent: boolean): string => {
  const status = formatStatus(app)
  const port = app.port ? `\x1b[90m:${app.port}\x1b[0m` : ''
  const prefix = indent ? '  ' : ''

  if (_showEmoji) {
    const icon = app.icon ?? '📦'
    return `${prefix}${icon} ${app.name} ${status}${port}`
  } else {
    return `${prefix}${status} ${app.name}${port}`
  }
}

const scheduleRender = () => {
  if (_renderTimer) return
  const elapsed = Date.now() - _lastRender
  const delay = Math.max(0, RENDER_DEBOUNCE - elapsed)
  _renderTimer = setTimeout(() => {
    _renderTimer = undefined
    render()
  }, delay)
}

function render() {
  if (!_enabled) return
  _lastRender = Date.now()

  const lines: string[] = []

  // Clear screen and move cursor to top
  lines.push('\x1b[2J\x1b[H')

  // Header
  lines.push(`\x1b[1m🐾 Toes\x1b[0m \x1b[90m${TOES_URL}\x1b[0m`)
  lines.push('')

  // Apps section
  const regularApps = _apps.filter(a => !a.tool)
  const tools = _apps.filter(a => a.tool)

  if (tools.length === 0) {
    // No tools, just list apps without header/indent
    for (const app of regularApps) {
      lines.push(formatAppLine(app, false))
    }
    lines.push('')
  } else {
    if (regularApps.length > 0) {
      lines.push('\x1b[1mApps\x1b[0m')
      for (const app of regularApps) {
        lines.push(formatAppLine(app, true))
      }
      lines.push('')
    }

    lines.push('\x1b[1mTools\x1b[0m')
    for (const app of tools) {
      lines.push(formatAppLine(app, true))
    }
    lines.push('')
  }

  process.stdout.write(lines.join('\n'))
}
