'use client'

import { FormEvent, useMemo, useState } from 'react'
import clsx from 'clsx'
import { Card } from '@/libs/frontend-ui-primitives'
import EntityBadge from '@/components/common/EntityBadge'
import { getExplorerApiBase } from '@/services/api/blockscout'
import type { ContractProfile, ContractSourceFile } from '@/services/api/contracts'

interface ContractCodeWorkspaceProps {
  address: string
  profile: ContractProfile
}

interface OutlineEntry {
  type: 'contract' | 'interface' | 'library' | 'function' | 'event' | 'error'
  name: string
  line: number
}

const QUICK_PROMPTS = [
  'What does this contract do?',
  'What are the functions available in this contract?',
  'Which functions can change state or move funds?',
  'Who has special permissions or control in this contract?',
  'What are potential risks or red flags in this contract?',
] as const

function makeFallbackSourceFile(profile: ContractProfile): ContractSourceFile | null {
  if (!profile.source_code_preview && !profile.abi_full && !profile.abi) return null
  return {
    path: profile.contract_name ? `${profile.contract_name}.sol` : 'Contract.sol',
    content: profile.source_code_full || profile.source_code_preview || profile.abi_full || profile.abi || '',
  }
}

function parseOutline(content: string): OutlineEntry[] {
  const entries: OutlineEntry[] = []
  content.split('\n').forEach((line, index) => {
    const lineNumber = index + 1
    const typeMatch = line.match(/^\s*(?:abstract\s+)?(contract|interface|library)\s+([A-Za-z_][A-Za-z0-9_]*)/)
    if (typeMatch) {
      entries.push({
        type: typeMatch[1] as OutlineEntry['type'],
        name: typeMatch[2],
        line: lineNumber,
      })
      return
    }

    const memberMatch = line.match(/^\s*(function|event|error)\s+([A-Za-z_][A-Za-z0-9_]*)/)
    if (memberMatch) {
      entries.push({
        type: memberMatch[1] as OutlineEntry['type'],
        name: memberMatch[2],
        line: lineNumber,
      })
    }
  })
  return entries
}

function sourceExcerptForPrompt(files: ContractSourceFile[]): string {
  return files
    .slice(0, 4)
    .map((file) => `File: ${file.path}\n${file.content.slice(0, 2600)}`)
    .join('\n\n')
    .slice(0, 5200)
}

export default function ContractCodeWorkspace({ address, profile }: ContractCodeWorkspaceProps) {
  const files = useMemo(() => {
    const normalized = profile.source_files?.length ? profile.source_files : []
    const fallback = makeFallbackSourceFile(profile)
    return normalized.length > 0 ? normalized : fallback ? [fallback] : []
  }, [profile])

  const [activeTab, setActiveTab] = useState<'source' | 'reader'>('source')
  const [activePath, setActivePath] = useState(files[0]?.path || '')
  const [prompt, setPrompt] = useState('What does this contract do?')
  const [model, setModel] = useState('Explorer AI')
  const [saveHistory, setSaveHistory] = useState(false)
  const [submitting, setSubmitting] = useState(false)
  const [readerAnswer, setReaderAnswer] = useState('')
  const [readerError, setReaderError] = useState('')
  const [expanded, setExpanded] = useState(false)

  const activeFile = files.find((file) => file.path === activePath) || files[0]
  const outline = useMemo(() => parseOutline(activeFile?.content || ''), [activeFile?.content])
  const sourceLines = useMemo(() => (activeFile?.content || '').split('\n'), [activeFile?.content])

  const selectedFiles = files
  const sourceAvailable = files.length > 0 && Boolean(activeFile?.content)

  const handleCopySource = async () => {
    if (!activeFile?.content || typeof navigator === 'undefined') return
    await navigator.clipboard?.writeText(activeFile.content)
  }

  const handleCopyLink = async () => {
    if (typeof navigator === 'undefined' || typeof window === 'undefined') return
    await navigator.clipboard?.writeText(`${window.location.href.split('#')[0]}#contract-source`)
  }

  const askReader = async (question: string) => {
    const trimmed = question.trim()
    if (!trimmed || submitting) return
    setPrompt(trimmed)
    setReaderError('')
    setReaderAnswer('')
    setSubmitting(true)

    try {
      const context = [
        `Contract address: ${address}`,
        profile.contract_name ? `Contract name: ${profile.contract_name}` : '',
        profile.compiler_version ? `Compiler: ${profile.compiler_version}` : '',
        profile.license_type ? `License: ${profile.license_type}` : '',
        profile.proxy_type ? `Proxy type: ${profile.proxy_type}` : '',
        `Read methods: ${profile.read_methods.map((method) => method.signature).slice(0, 24).join(', ') || 'none reported'}`,
        `Write methods: ${profile.write_methods.map((method) => method.signature).slice(0, 24).join(', ') || 'none reported'}`,
        sourceAvailable ? `Verified source excerpts:\n${sourceExcerptForPrompt(selectedFiles)}` : 'Verified source text is not available.',
      ].filter(Boolean).join('\n')

      const response = await fetch(`${getExplorerApiBase()}/api/v1/ai/chat`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          messages: [
            {
              role: 'user',
              content: `${trimmed}\n\nUse this contract context and answer concisely. Do not invent behavior that is not supported by the ABI or source.\n\n${context}`,
            },
          ],
          pageContext: {
            path: `/addresses/${address}`,
            view: 'contract-code-reader',
            address,
          },
        }),
      })

      const payload = await response.json().catch(() => null)
      if (!response.ok) {
        throw new Error(payload?.error?.message || `AI reader returned HTTP ${response.status}`)
      }
      setReaderAnswer(String(payload?.reply || payload?.message?.content || 'No answer returned.'))
    } catch (error) {
      setReaderError(error instanceof Error ? error.message : 'Code Reader is temporarily unavailable.')
    } finally {
      setSubmitting(false)
    }
  }

  const handleSubmit = async (event: FormEvent) => {
    event.preventDefault()
    await askReader(prompt)
  }

  if (!sourceAvailable && !profile.abi_available) {
    return null
  }

  return (
    <Card className="mb-6" title="Contract Source Code">
      <section id="contract-source" className="space-y-4">
        <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
          <div className="flex flex-wrap gap-2">
            <button
              type="button"
              onClick={() => setActiveTab('source')}
              className={clsx(
                'rounded-lg px-3 py-2 text-sm font-semibold transition',
                activeTab === 'source'
                  ? 'bg-primary-600 text-white'
                  : 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-gray-900 dark:text-gray-200 dark:hover:bg-gray-700',
              )}
            >
              Source
            </button>
            <button
              type="button"
              onClick={() => setActiveTab('reader')}
              className={clsx(
                'rounded-lg px-3 py-2 text-sm font-semibold transition',
                activeTab === 'reader'
                  ? 'bg-primary-600 text-white'
                  : 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-gray-900 dark:text-gray-200 dark:hover:bg-gray-700',
              )}
            >
              Code Reader
            </button>
          </div>
          <div className="flex flex-wrap gap-2">
            {profile.source_verified ? <EntityBadge label="verified source" tone="success" /> : null}
            {profile.abi_available ? <EntityBadge label="abi available" tone="info" /> : null}
            {profile.compiler_version ? <EntityBadge label={profile.compiler_version} tone="neutral" className="normal-case tracking-normal" /> : null}
          </div>
        </div>

        {activeTab === 'source' ? (
          <div className={clsx('overflow-hidden rounded-lg border border-gray-200 dark:border-gray-700', expanded ? 'min-h-[46rem]' : '')}>
            <div className="grid lg:grid-cols-[18rem_minmax(0,1fr)]">
              <aside className="border-b border-gray-200 bg-gray-50 dark:border-gray-700 dark:bg-gray-900 lg:border-b-0 lg:border-r">
                <div className="flex items-center justify-between border-b border-gray-200 px-4 py-3 text-xs font-semibold uppercase text-gray-500 dark:border-gray-700 dark:text-gray-400">
                  <span>Explorer</span>
                  <span>{files.length} file{files.length === 1 ? '' : 's'}</span>
                </div>
                <div className="max-h-72 overflow-auto p-2 lg:max-h-[34rem]">
                  {files.map((file) => (
                    <button
                      type="button"
                      key={file.path}
                      onClick={() => setActivePath(file.path)}
                      className={clsx(
                        'block w-full rounded-md px-3 py-2 text-left text-sm transition',
                        file.path === activeFile?.path
                          ? 'bg-white font-semibold text-gray-950 shadow-sm dark:bg-gray-800 dark:text-white'
                          : 'text-gray-700 hover:bg-white dark:text-gray-300 dark:hover:bg-gray-800',
                      )}
                    >
                      <span className="block truncate">{file.path}</span>
                    </button>
                  ))}
                </div>
                {outline.length > 0 ? (
                  <div className="border-t border-gray-200 p-2 dark:border-gray-700">
                    <div className="px-3 py-2 text-xs font-semibold uppercase text-gray-500 dark:text-gray-400">Outline</div>
                    <div className="max-h-64 overflow-auto">
                      {outline.slice(0, 80).map((entry) => (
                        <button
                          key={`${entry.type}-${entry.name}-${entry.line}`}
                          type="button"
                          onClick={() => document.getElementById(`source-line-${entry.line}`)?.scrollIntoView({ block: 'center' })}
                          className="flex w-full items-center gap-2 rounded-md px-3 py-1.5 text-left text-xs text-gray-700 hover:bg-white dark:text-gray-300 dark:hover:bg-gray-800"
                        >
                          <span className="w-16 uppercase text-gray-400">{entry.type}</span>
                          <span className="min-w-0 flex-1 truncate font-mono">{entry.name}</span>
                          <span className="text-gray-400">{entry.line}</span>
                        </button>
                      ))}
                    </div>
                  </div>
                ) : null}
              </aside>

              <div className="min-w-0 bg-gray-950 text-gray-100">
                <div className="flex flex-col gap-3 border-b border-gray-800 bg-gray-900 px-4 py-3 sm:flex-row sm:items-center sm:justify-between">
                  <div className="min-w-0">
                    <div className="truncate font-mono text-sm text-white">{activeFile?.path || 'Source'}</div>
                    <div className="mt-1 text-xs text-gray-400">{sourceLines.length} lines</div>
                  </div>
                  <div className="flex flex-wrap gap-2">
                    <button type="button" onClick={handleCopySource} className="rounded-md border border-gray-700 px-3 py-1.5 text-xs font-semibold text-gray-200 hover:bg-gray-800">
                      Copy
                    </button>
                    <button type="button" onClick={handleCopyLink} className="rounded-md border border-gray-700 px-3 py-1.5 text-xs font-semibold text-gray-200 hover:bg-gray-800">
                      Link
                    </button>
                    <button type="button" onClick={() => setExpanded((value) => !value)} className="rounded-md border border-gray-700 px-3 py-1.5 text-xs font-semibold text-gray-200 hover:bg-gray-800">
                      {expanded ? 'Collapse' : 'Expand'}
                    </button>
                  </div>
                </div>
                <pre className={clsx('overflow-auto p-0 text-xs leading-5', expanded ? 'max-h-[52rem]' : 'max-h-[34rem]')}>
                  <code className="block min-w-max py-4">
                    {sourceLines.map((line, index) => (
                      <span id={`source-line-${index + 1}`} key={`${activeFile?.path}-${index}`} className="grid grid-cols-[4.5rem_minmax(0,1fr)] px-4 hover:bg-white/5">
                        <span className="select-none pr-4 text-right text-gray-500">{index + 1}</span>
                        <span className="whitespace-pre text-gray-100">{line || ' '}</span>
                      </span>
                    ))}
                  </code>
                </pre>
              </div>
            </div>
          </div>
        ) : (
          <div className="rounded-lg border border-gray-200 p-4 dark:border-gray-700">
            <form onSubmit={handleSubmit} className="grid gap-5 lg:grid-cols-[28rem_minmax(0,1fr)]">
              <div className="space-y-4 lg:border-r lg:border-gray-200 lg:pr-5 lg:dark:border-gray-700">
                <label className="block">
                  <span className="mb-2 block text-sm font-semibold text-gray-900 dark:text-white">Choose Model</span>
                  <select
                    value={model}
                    onChange={(event) => setModel(event.target.value)}
                    className="w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-950 dark:text-white"
                  >
                    <option>Explorer AI</option>
                    <option>Grok</option>
                  </select>
                </label>
                <div>
                  <div className="mb-2 text-sm font-semibold text-gray-900 dark:text-white">File Browser</div>
                  <div className="space-y-2 rounded-lg bg-gray-50 p-3 dark:bg-gray-900">
                    {files.map((file) => (
                      <label key={file.path} className="flex items-center gap-2 text-sm text-gray-700 dark:text-gray-200">
                        <input type="checkbox" checked readOnly className="h-4 w-4 rounded border-gray-300 text-primary-600" />
                        <span className="truncate">{file.path}</span>
                      </label>
                    ))}
                  </div>
                </div>
              </div>
              <div className="min-w-0 space-y-4">
                <div className="flex items-center justify-between gap-3">
                  <div className="text-sm font-semibold text-gray-900 dark:text-white">Prompt</div>
                  <label className="flex items-center gap-2 text-xs text-gray-600 dark:text-gray-300">
                    <input type="checkbox" checked={saveHistory} onChange={(event) => setSaveHistory(event.target.checked)} className="h-4 w-4 rounded border-gray-300 text-primary-600" />
                    Save History
                  </label>
                </div>
                <div className="flex gap-3">
                  <textarea
                    value={prompt}
                    onChange={(event) => setPrompt(event.target.value)}
                    rows={3}
                    className="min-h-24 flex-1 rounded-lg border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-950 dark:text-white"
                  />
                  <button
                    type="submit"
                    disabled={submitting || !prompt.trim()}
                    className="h-12 rounded-lg bg-primary-600 px-4 text-sm font-semibold text-white transition hover:bg-primary-700 disabled:cursor-not-allowed disabled:opacity-60"
                  >
                    {submitting ? '...' : 'Send'}
                  </button>
                </div>
                <div className="flex flex-wrap gap-2">
                  {QUICK_PROMPTS.map((quickPrompt) => (
                    <button
                      key={quickPrompt}
                      type="button"
                      onClick={() => void askReader(quickPrompt)}
                      className="rounded-full border border-gray-300 px-3 py-1.5 text-xs font-semibold text-gray-700 hover:border-primary-400 hover:text-primary-700 dark:border-gray-700 dark:text-gray-300 dark:hover:text-primary-300"
                    >
                      {quickPrompt}
                    </button>
                  ))}
                </div>
                {readerAnswer ? (
                  <div className="whitespace-pre-wrap rounded-lg bg-gray-50 p-4 text-sm text-gray-800 dark:bg-gray-900 dark:text-gray-100">
                    {readerAnswer}
                  </div>
                ) : null}
                {readerError ? (
                  <div className="rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-200">
                    {readerError}
                  </div>
                ) : null}
              </div>
            </form>
          </div>
        )}
      </section>
    </Card>
  )
}
