/*
 *  CompareView.tsx
 *  Zyquo Cloud Web
 *
 *  Author: Simon-Pierre Boucher
 *  Mail: contact@spboucher.ai
 *
 *  Multi-model compare: one prompt broadcast to 2–4 models in side-by-side
 *  columns, each streaming independently with its own Stop/copy/regenerate,
 *  plus "promote this answer into the thread".
 */

import { useMemo, useRef, useState } from 'react'
import { CATALOG, defaultModel, pricedCost } from '../features/catalogHelpers'
import { clientFor } from '../providers/registry'
import { ProviderError } from '../providers/types'
import { uid, useStore } from '../state/store'
import { getKey } from '../storage/keys'
import type { AIModel, Message } from '../types'
import ModelMenu from './ModelMenu'
import { Markdown } from './Markdown'
import {
  IconChevronDown,
  IconCopy,
  IconPlus,
  IconRefresh,
  IconSend,
  IconStop,
  IconX,
  ProviderGlyph,
} from './icons'

interface Column {
  id: string
  model: AIModel
  text: string
  reasoning: string
  error: string | null
  streaming: boolean
  outputTokens: number | null
  abort: AbortController | null
}

function freshColumn(model: AIModel): Column {
  return {
    id: uid(),
    model,
    text: '',
    reasoning: '',
    error: null,
    streaming: false,
    outputTokens: null,
    abort: null,
  }
}

export default function CompareView({ onClose }: { onClose: () => void }) {
  const keyedProviders = useStore((s) => s.keyedProviders)
  const selectedID = useStore((s) => s.selectedID)
  const toast = useStore((s) => s.toast)

  const seeds = useMemo(() => {
    const keyed = CATALOG.filter((m) => m.isRecommended && keyedProviders.includes(m.provider))
    const picks = keyed.slice(0, 2)
    while (picks.length < 2) picks.push(defaultModel())
    return picks
  }, [keyedProviders])

  const [columns, setColumns] = useState<Column[]>(() => seeds.map(freshColumn))
  const [prompt, setPrompt] = useState('')
  const [lastPrompt, setLastPrompt] = useState('')
  const [menuFor, setMenuFor] = useState<string | null>(null)
  const columnsRef = useRef(columns)
  columnsRef.current = columns

  const patchColumn = (id: string, patch: Partial<Column>) => {
    setColumns((cols) => cols.map((c) => (c.id === id ? { ...c, ...patch } : c)))
  }

  const runColumn = async (column: Column, text: string) => {
    const apiKey = getKey(column.model.provider)
    if (!apiKey) {
      patchColumn(column.id, { error: ProviderError.missingAPIKey(column.model.provider).message })
      return
    }
    const abort = new AbortController()
    patchColumn(column.id, {
      text: '',
      reasoning: '',
      error: null,
      streaming: true,
      outputTokens: null,
      abort,
    })
    const message: Message = { id: uid(), role: 'user', text, createdAt: Date.now() }
    try {
      const events = clientFor(column.model).streamChat(
        { model: column.model, messages: [message], parameters: {}, stream: true },
        apiKey,
        abort.signal
      )
      for await (const event of events) {
        const current = columnsRef.current.find((c) => c.id === column.id)
        if (!current) break
        if (event.type === 'textDelta') {
          patchColumn(column.id, { text: current.text + event.text })
        } else if (event.type === 'reasoningDelta') {
          patchColumn(column.id, { reasoning: current.reasoning + event.text })
        } else if (event.type === 'usage') {
          patchColumn(column.id, { outputTokens: event.usage.outputTokens })
        }
      }
    } catch (err) {
      if (!(err instanceof ProviderError && err.kind === 'cancelled')) {
        patchColumn(column.id, { error: err instanceof Error ? err.message : String(err) })
      }
    } finally {
      patchColumn(column.id, { streaming: false, abort: null })
    }
  }

  const broadcast = () => {
    const text = prompt.trim()
    if (text === '') return
    setLastPrompt(text)
    setPrompt('')
    for (const column of columnsRef.current) void runColumn(column, text)
  }

  const promote = (column: Column) => {
    const state = useStore.getState()
    const conversationID = selectedID ?? state.newConversation({ model: column.model }).id
    const conversation = state.conversations.find((c) => c.id === conversationID)
    if (!conversation) return
    const userMessage: Message = {
      id: uid(),
      role: 'user',
      text: lastPrompt,
      createdAt: Date.now(),
    }
    const assistantMessage: Message = {
      id: uid(),
      role: 'assistant',
      text: column.text,
      ...(column.reasoning !== '' ? { reasoning: column.reasoning } : {}),
      modelID: column.model.id,
      provider: column.model.provider,
      ...(column.outputTokens !== null
        ? {
            usage: { inputTokens: 0, outputTokens: column.outputTokens },
            estimatedCost: pricedCost(column.model, {
              inputTokens: 0,
              outputTokens: column.outputTokens,
            }),
          }
        : {}),
      createdAt: Date.now(),
    }
    state.updateConversation(conversationID, {
      messages: [...conversation.messages, userMessage, assistantMessage],
    })
    toast(`Promoted ${column.model.displayName}'s answer into the thread`, 'success')
    onClose()
  }

  return (
    <div className="overlay" onMouseDown={(e) => e.target === e.currentTarget && onClose()}>
      <div className="panel" style={{ width: 'min(1180px, 96vw)', height: '84vh', maxHeight: '84vh' }}>
        <div className="panel-search" style={{ justifyContent: 'space-between' }}>
          <strong style={{ fontSize: 14 }}>Compare Models</strong>
          <span style={{ display: 'flex', gap: 8 }}>
            <button
              className="button"
              disabled={columns.length >= 4}
              onClick={() => setColumns((cols) => [...cols, freshColumn(defaultModel())])}
            >
              <IconPlus size={10} /> Add column
            </button>
            <button className="button" onClick={onClose}>
              Done
            </button>
          </span>
        </div>
        <div style={{ flex: 1, display: 'flex', minHeight: 0 }}>
          {columns.map((column, index) => (
            <div
              key={column.id}
              style={{
                flex: 1,
                minWidth: 0,
                display: 'flex',
                flexDirection: 'column',
                borderLeft: index > 0 ? 'var(--z-hairline) solid var(--z-border)' : 'none',
              }}
            >
              <div
                style={{
                  display: 'flex',
                  alignItems: 'center',
                  gap: 4,
                  padding: '4px 8px',
                  borderBottom: 'var(--z-hairline) solid var(--z-border)',
                }}
              >
                <button className="model-chip" onClick={() => setMenuFor(column.id)}>
                  <span className="glyph">
                    <ProviderGlyph provider={column.model.provider} />
                  </span>
                  {column.model.displayName}
                  <span className="chevron">
                    <IconChevronDown />
                  </span>
                </button>
                <span style={{ marginLeft: 'auto', fontSize: 11, color: 'var(--z-text-tertiary)' }}>
                  {column.outputTokens !== null ? `${column.outputTokens} tok` : ''}
                </span>
                {column.streaming ? (
                  <button className="icon-button" title="Stop" onClick={() => column.abort?.abort()}>
                    <IconStop size={9} />
                  </button>
                ) : (
                  <>
                    {column.text !== '' && (
                      <>
                        <button
                          className="icon-button"
                          title="Copy answer"
                          onClick={() => void navigator.clipboard.writeText(column.text)}
                        >
                          <IconCopy size={10} />
                        </button>
                        <button
                          className="icon-button"
                          title="Promote into thread"
                          onClick={() => promote(column)}
                        >
                          <IconSend size={10} />
                        </button>
                      </>
                    )}
                    <button
                      className="icon-button"
                      title="Regenerate"
                      disabled={lastPrompt === ''}
                      onClick={() => lastPrompt !== '' && void runColumn(column, lastPrompt)}
                    >
                      <IconRefresh size={10} />
                    </button>
                  </>
                )}
                {columns.length > 2 && (
                  <button
                    className="icon-button"
                    title="Remove column"
                    onClick={() => {
                      column.abort?.abort()
                      setColumns((cols) => cols.filter((c) => c.id !== column.id))
                    }}
                  >
                    <IconX size={9} />
                  </button>
                )}
              </div>
              <div style={{ flex: 1, overflowY: 'auto', padding: 12 }}>
                {column.reasoning !== '' && (
                  <div
                    style={{
                      fontFamily: 'var(--z-font-mono)',
                      fontSize: 'calc(var(--z-chat-font-size) - 2.5px)',
                      color: 'var(--z-text-tertiary)',
                      marginBottom: 8,
                      maxHeight: 96,
                      overflow: 'hidden',
                    }}
                  >
                    {column.reasoning}
                  </div>
                )}
                {column.error ? (
                  <div style={{ color: 'var(--z-danger)', fontSize: 12.5 }}>{column.error}</div>
                ) : (
                  <>
                    <Markdown text={column.text} />
                    {column.streaming && <span className="streaming-caret" />}
                  </>
                )}
              </div>
            </div>
          ))}
        </div>
        <div
          style={{
            display: 'flex',
            gap: 8,
            padding: 12,
            borderTop: 'var(--z-hairline) solid var(--z-border)',
          }}
        >
          <textarea
            className="input-editor"
            style={{ flex: 1, maxHeight: 120 }}
            rows={1}
            placeholder="Prompt all models…"
            value={prompt}
            onChange={(e) => setPrompt(e.target.value)}
            onKeyDown={(e) => {
              if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault()
                broadcast()
              }
            }}
          />
          <button className="send-button" disabled={prompt.trim() === ''} onClick={broadcast}>
            <IconSend />
          </button>
        </div>
        {menuFor && (
          <ModelMenu
            title="Pick a model for this column"
            onPick={(model) => patchColumn(menuFor, { model })}
            onClose={() => setMenuFor(null)}
          />
        )}
      </div>
    </div>
  )
}
