<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { Terminal } from '@xterm/xterm'
import { FitAddon } from '@xterm/addon-fit'
import { WebLinksAddon } from '@xterm/addon-web-links'
import '@xterm/xterm/css/xterm.css'

const terminalContainer = ref<HTMLElement | null>(null)
const connected = ref(false)
const connecting = ref(false)
const error = ref<string | null>(null)
const sessionId = ref<string | null>(null)
const isResumedSession = ref(false)

let terminal: Terminal | null = null
let fitAddon: FitAddon | null = null
let socket: WebSocket | null = null
let resizeObserver: ResizeObserver | null = null

const WS_URL = `ws://${window.location.hostname}:4103`

function initTerminal() {
  if (!terminalContainer.value) return

  terminal = new Terminal({
    cursorBlink: true,
    cursorStyle: 'block',
    fontSize: 14,
    fontFamily: "'JetBrains Mono', 'Fira Code', Consolas, monospace",
    theme: {
      background: '#0f0f14',
      foreground: '#e4e4e7',
      cursor: '#6366f1',
      cursorAccent: '#0f0f14',
      selectionBackground: 'rgba(99, 102, 241, 0.3)',
      black: '#16161d',
      red: '#ef4444',
      green: '#22c55e',
      yellow: '#eab308',
      blue: '#3b82f6',
      magenta: '#a855f7',
      cyan: '#06b6d4',
      white: '#e4e4e7',
      brightBlack: '#52525b',
      brightRed: '#f87171',
      brightGreen: '#4ade80',
      brightYellow: '#facc15',
      brightBlue: '#60a5fa',
      brightMagenta: '#c084fc',
      brightCyan: '#22d3ee',
      brightWhite: '#ffffff'
    },
    allowProposedApi: true
  })

  fitAddon = new FitAddon()
  terminal.loadAddon(fitAddon)
  terminal.loadAddon(new WebLinksAddon())

  terminal.open(terminalContainer.value)
  fitAddon.fit()

  // Handle resize
  resizeObserver = new ResizeObserver(() => {
    if (fitAddon && terminal) {
      fitAddon.fit()
      if (socket && socket.readyState === WebSocket.OPEN) {
        socket.send(JSON.stringify({
          type: 'resize',
          cols: terminal.cols,
          rows: terminal.rows
        }))
      }
    }
  })
  resizeObserver.observe(terminalContainer.value)

  // Handle terminal input
  terminal.onData((data) => {
    if (socket && socket.readyState === WebSocket.OPEN) {
      socket.send(JSON.stringify({ type: 'input', data }))
    }
  })
}

async function connect() {
  if (connecting.value) return

  connecting.value = true
  error.value = null

  try {
    socket = new WebSocket(WS_URL)

    socket.onopen = () => {
      connected.value = true
      connecting.value = false
      terminal?.focus()

      // Send initial resize
      if (terminal) {
        socket?.send(JSON.stringify({
          type: 'resize',
          cols: terminal.cols,
          rows: terminal.rows
        }))
      }
    }

    socket.onmessage = (event) => {
      const msg = JSON.parse(event.data)
      if (msg.type === 'connected') {
        sessionId.value = msg.sessionId
        isResumedSession.value = !msg.isNew
        if (!msg.isNew) {
          terminal?.write('\x1b[36m[Reconnected to existing session]\x1b[0m\r\n')
        }
      } else if (msg.type === 'replay') {
        // Replay buffer from persistent session
        terminal?.write(msg.data)
      } else if (msg.type === 'output') {
        terminal?.write(msg.data)
      } else if (msg.type === 'exit') {
        terminal?.write(msg.data)
        sessionId.value = null
      } else if (msg.type === 'error') {
        error.value = msg.message
        terminal?.write(`\r\n\x1b[31mError: ${msg.message}\x1b[0m\r\n`)
      }
    }

    socket.onclose = () => {
      connected.value = false
      connecting.value = false
      if (sessionId.value) {
        terminal?.write('\r\n\x1b[33mDisconnected - session preserved on server\x1b[0m\r\n')
      } else {
        terminal?.write('\r\n\x1b[33mConnection closed\x1b[0m\r\n')
      }
    }

    socket.onerror = () => {
      error.value = 'WebSocket connection failed. Make sure terminal server is running.'
      connecting.value = false
    }
  } catch (e: any) {
    error.value = e.message
    connecting.value = false
  }
}

function disconnect() {
  if (socket) {
    socket.close()
    socket = null
  }
  connected.value = false
}

function clearTerminal() {
  terminal?.clear()
  terminal?.reset()
}

async function copyContent() {
  if (!terminal) return

  // Get all terminal content
  const buffer = terminal.buffer.active
  let content = ''

  for (let i = 0; i < buffer.length; i++) {
    const line = buffer.getLine(i)
    if (line) {
      content += line.translateToString(true) + '\n'
    }
  }

  try {
    await navigator.clipboard.writeText(content.trim())
    // Visual feedback
    const btn = document.querySelector('.btn-copy') as HTMLButtonElement
    if (btn) {
      btn.classList.add('copied')
      setTimeout(() => btn.classList.remove('copied'), 1500)
    }
  } catch (e) {
    console.error('Failed to copy:', e)
  }
}

function runClaudeCode() {
  if (socket && socket.readyState === WebSocket.OPEN) {
    socket.send(JSON.stringify({ type: 'input', data: 'claude\r' }))
  }
}

onMounted(async () => {
  await nextTick()
  initTerminal()
  // Auto-connect
  connect()
})

onBeforeUnmount(() => {
  resizeObserver?.disconnect()
  socket?.close()
  terminal?.dispose()
})
</script>

<template>
  <div class="terminal-page">
    <!-- Toolbar -->
    <div class="terminal-toolbar">
      <div class="toolbar-left">
        <h2>Terminal</h2>
        <span v-if="connected" class="status connected">
          Connected
          <span v-if="sessionId" class="session-badge">{{ sessionId }}</span>
        </span>
        <span v-else-if="connecting" class="status connecting">Connecting...</span>
        <span v-else class="status disconnected">
          Disconnected
          <span v-if="sessionId" class="session-hint">(session active on server)</span>
        </span>
      </div>

      <div class="toolbar-actions">
        <button
          v-if="!connected"
          class="btn-primary"
          @click="connect"
          :disabled="connecting"
        >
          Connect
        </button>
        <button
          v-else
          class="btn-secondary"
          @click="disconnect"
        >
          Disconnect
        </button>

        <button
          class="btn-accent"
          @click="runClaudeCode"
          :disabled="!connected"
          title="Run Claude Code"
        >
          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <path d="M12 2L2 7l10 5 10-5-10-5z"/>
            <path d="M2 17l10 5 10-5"/>
            <path d="M2 12l10 5 10-5"/>
          </svg>
          Claude
        </button>

        <button
          class="btn-icon btn-copy"
          @click="copyContent"
          title="Copy terminal content"
        >
          <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
          </svg>
        </button>

        <button
          class="btn-icon"
          @click="clearTerminal"
          title="Clear terminal"
        >
          <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <path d="M3 6h18"/>
            <path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/>
            <path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/>
          </svg>
        </button>
      </div>
    </div>

    <!-- Error message -->
    <div v-if="error && !connected" class="error-banner">
      {{ error }}
      <p class="error-hint">Make sure the server is running with <code>bun start</code> in the server folder</p>
    </div>

    <!-- Terminal container -->
    <div ref="terminalContainer" class="terminal-container"></div>
  </div>
</template>

<style scoped>
.terminal-page {
  display: flex;
  flex-direction: column;
  flex: 1;
  overflow: hidden;
  background: #0f0f14;
}

.terminal-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1rem;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border-color);
}

.toolbar-left {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.toolbar-left h2 {
  margin: 0;
  font-size: 1rem;
  color: var(--text-primary);
}

.status {
  font-size: 0.75rem;
  padding: 0.25rem 0.625rem;
  border-radius: 9999px;
  font-weight: 500;
}

.status.connected {
  background: var(--success-bg);
  color: var(--success);
}

.status.connecting {
  background: var(--warning-bg);
  color: var(--warning);
}

.status.disconnected {
  background: var(--error-bg);
  color: var(--error);
}

.session-badge {
  margin-left: 0.5rem;
  padding: 0.125rem 0.375rem;
  background: rgba(255, 255, 255, 0.15);
  border-radius: 4px;
  font-size: 0.7rem;
  font-family: var(--font-mono);
}

.session-hint {
  margin-left: 0.25rem;
  font-size: 0.7rem;
  opacity: 0.8;
}

.toolbar-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.btn-primary {
  padding: 0.5rem 1rem;
  background: var(--accent);
  color: white;
  border: none;
  border-radius: 6px;
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s;
}

.btn-primary:hover:not(:disabled) {
  background: var(--accent-hover);
}

.btn-primary:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.btn-secondary {
  padding: 0.5rem 1rem;
  background: var(--bg-hover);
  color: var(--text-primary);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
}

.btn-secondary:hover {
  background: var(--bg-tertiary);
}

.btn-accent {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
  color: white;
  border: none;
  border-radius: 6px;
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  transition: opacity 0.15s;
}

.btn-accent:hover:not(:disabled) {
  opacity: 0.9;
}

.btn-accent:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-icon {
  padding: 0.5rem;
  background: transparent;
  border: none;
  border-radius: 6px;
  color: var(--text-secondary);
  cursor: pointer;
}

.btn-icon:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}

.btn-icon.btn-copy.copied {
  color: var(--success);
  background: var(--success-bg);
}

.error-banner {
  padding: 1rem;
  background: var(--error-bg);
  color: var(--error);
  font-size: 0.875rem;
  border-bottom: 1px solid var(--error);
}

.error-hint {
  margin: 0.5rem 0 0;
  font-size: 0.8rem;
  opacity: 0.8;
}

.error-hint code {
  background: rgba(0, 0, 0, 0.2);
  padding: 0.125rem 0.375rem;
  border-radius: 4px;
  font-family: var(--font-mono);
}

.terminal-container {
  flex: 1;
  padding: 0.5rem;
  overflow: hidden;
}

/* xterm overrides */
.terminal-container :deep(.xterm) {
  height: 100%;
  padding: 0.5rem;
}

.terminal-container :deep(.xterm-viewport) {
  overflow-y: auto !important;
}

.terminal-container :deep(.xterm-viewport::-webkit-scrollbar) {
  width: 10px;
}

.terminal-container :deep(.xterm-viewport::-webkit-scrollbar-track) {
  background: #16161d;
}

.terminal-container :deep(.xterm-viewport::-webkit-scrollbar-thumb) {
  background: #2a2a3a;
  border-radius: 5px;
}

.terminal-container :deep(.xterm-viewport::-webkit-scrollbar-thumb:hover) {
  background: #3a3a4a;
}
</style>
