import { useEffect, useMemo, useRef } from 'react'
import useAppStore from '../store/appStore'

const KIND_COLOR = {
  frontend: '#60a5fa',
  backend:  '#34d399',
  install:  '#f59e0b',
}

// Heuristic: lines that look like real errors / stack traces.  Intentionally
// broad — false positives just mean the user gets a "Fix" affordance on a
// harmless line, which they can ignore.  False negatives are worse.
const ERROR_RE = /\b(error|exception|traceback|enoent|cannot find module|syntaxerror|typeerror|referenceerror|fatal)\b|^✗|^\s*at\s+\S+\s*\(/i

// Common false positives we'd rather not light up: log lines that explicitly
// report success/no-error, and the literal word "error" in non-error context.
const NOT_ERROR_RE = /\b(no errors?|0 errors?|error[-_]free)\b/i

function isErrorLine(line) {
  if (!line) return false
  if (NOT_ERROR_RE.test(line)) return false
  return ERROR_RE.test(line)
}

// Bundle a window of context around an error line — a few lines before, the
// hit, a few after.  The agent has `read_logs` if it needs more, but this
// gives it enough to start without an extra tool roundtrip.
function buildContext(logs, idx, before = 6, after = 4) {
  const start = Math.max(0, idx - before)
  const end   = Math.min(logs.length, idx + after + 1)
  return logs.slice(start, end)
    .map((e) => `[${e.kind}] ${e.line}`)
    .join('\n')
}

function FixPill({ onClick, disabled }) {
  return (
    <button
      onClick={(e) => { e.stopPropagation(); onClick() }}
      disabled={disabled}
      className="opacity-0 group-hover:opacity-100 transition-opacity shrink-0 ml-2 px-2 py-0.5 text-[10px] font-semibold rounded border mono disabled:opacity-30"
      style={{
        background:  'rgba(239, 68, 68, 0.12)',
        borderColor: 'rgba(239, 68, 68, 0.4)',
        color:       '#fca5a5',
        userSelect:  'none',
      }}
      title="Send this error to the AI and have it fix the root cause"
    >
      ✦ Fix with AI
    </button>
  )
}

export default function LogsPanel() {
  const logs              = useAppStore((s) => s.runtime.logs)
  const mode              = useAppStore((s) => s.mode)
  const setMode           = useAppStore((s) => s.setMode)
  const setComposerDraft  = useAppStore((s) => s.setComposerDraft)
  const activeFile        = useAppStore((s) => s.project.activeFile)
  const showToast         = useAppStore((s) => s.showToast)
  const isStreaming       = useAppStore((s) => s.isStreaming)
  const bottomRef         = useRef(null)

  useEffect(() => {
    bottomRef.current?.scrollIntoView({ behavior: 'instant' })
  }, [logs.length])

  // Memoize the error flags so we don't re-regex on every render of every row.
  const errorMask = useMemo(
    () => logs.map((e) => isErrorLine(e.line)),
    [logs],
  )

  function fixThis(idx) {
    const ctx = buildContext(logs, idx)
    const entry = logs[idx]
    const kindLabel = entry?.kind === 'install' ? 'install step'
                    : entry?.kind === 'backend' ? 'backend dev server'
                    : entry?.kind === 'frontend' ? 'frontend dev server'
                    : 'dev server'

    const text =
`The ${kindLabel} just emitted an error. Here's the log window around it:

\`\`\`
${ctx}
\`\`\`

Find the file(s) involved, read them, and fix the root cause. Use \`read_logs\` if you need broader context.`

    // Auto-pin the active file if there is one — it's usually what the user
    // was just editing and likely the source of the regression.
    const pins = activeFile ? [activeFile] : []
    setComposerDraft({ text, pinnedFiles: pins })

    // If we're in CODE mode, flip to VIBE so the composer is visible and the
    // draft actually lands somewhere the user can see.
    if (mode !== 'vibe') setMode('vibe')

    showToast('Sent to chat — review and press Enter')
  }

  return (
    <div
      style={{
        height: '100%',
        overflowY: 'auto',
        background: 'var(--code-bg)',
        padding: '8px 12px',
        fontFamily: 'ui-monospace, "JetBrains Mono", monospace',
        fontSize: 11.5,
        color: 'var(--code-text)',
        lineHeight: 1.7,
      }}
    >
      {logs.length === 0 ? (
        <div style={{ color: 'var(--text-faint)', paddingTop: 4 }}>
          No logs yet. Click Run to start the dev servers.
        </div>
      ) : (
        logs.map((entry, i) => {
          const isError = errorMask[i]
          return (
            <div
              key={i}
              className={isError ? 'group' : ''}
              style={{
                display:    'flex',
                gap:        8,
                alignItems: 'flex-start',
                whiteSpace: 'pre-wrap',
                wordBreak:  'break-all',
                background: isError ? 'rgba(239, 68, 68, 0.06)' : 'transparent',
                margin:     isError ? '0 -12px' : 0,
                padding:    isError ? '0 12px' : 0,
                borderLeft: isError ? '2px solid rgba(239, 68, 68, 0.4)' : '2px solid transparent',
              }}
            >
              <span style={{ color: KIND_COLOR[entry.kind] ?? '#6b7280', flexShrink: 0, minWidth: 72, userSelect: 'none' }}>
                [{entry.kind}]
              </span>
              <span style={{ color: 'var(--code-text)', flex: 1, minWidth: 0 }}>
                {entry.line}
              </span>
              {isError && (
                <FixPill
                  onClick={() => fixThis(i)}
                  disabled={isStreaming}
                />
              )}
            </div>
          )
        })
      )}
      <div ref={bottomRef} />
    </div>
  )
}
