'use client'

import { useState, useEffect, useCallback, useRef } from 'react'
import { X, FileText, Folder, Save, WrapText, ExternalLink } from 'lucide-react'
import { cn } from '@/lib/utils'
import { CodeMirrorEditor } from '@/components/ui/codemirror-editor'
import { useWordWrap } from '@/hooks/use-word-wrap'
import { MarkdownPreview } from '@/components/ui/markdown-preview'
import { HtmlPreview } from '@/components/ui/html-preview'
import { JsonPreview } from '@/components/ui/json-preview'
import { VideoPreview } from '@/components/ui/video-preview'
import { AudioPreview } from '@/components/ui/audio-preview'
import { PdfPreview } from '@/components/ui/pdf-preview'
import { SvgPreview } from '@/components/ui/svg-preview'
import { BinaryPreview } from '@/components/ui/binary-preview'
import { useI18n } from '@/components/providers/i18n-provider'
import { detectFileType, getLanguageFromFilename, type FileCategory } from '@/lib/file-types'

type EditorMode = 'edit' | 'preview'

type FileKind = 'forge-config' | 'forge-subdir' | 'sub-agent' | 'project'

function getFileKind(filename: string): FileKind {
  if (filename.startsWith('.claude/')) {
    const inner = filename.slice('.claude/'.length)
    if (inner.startsWith('agents/')) return 'sub-agent'
    if (inner.startsWith('memory/') || inner.startsWith('skills/')) return 'forge-subdir'
    return 'forge-config'
  }
  return 'project'
}

/** Strip .claude/ prefix to get the inner path used by forge APIs */
function toInnerPath(filename: string): string {
  return filename.startsWith('.claude/') ? filename.slice('.claude/'.length) : filename
}

/**
 * Build a raw URL for media files (image, video, audio, pdf).
 * Returns empty string for text/code files that don't need raw access.
 */
function buildRawUrl(workspaceId: string, filename: string, kind: FileKind, inner: string): string {
  if (kind === 'project') {
    return `/api/workspaces/${workspaceId}/raw?path=${encodeURIComponent(filename)}`
  }
  return `/api/workspaces/${workspaceId}/raw?name=${encodeURIComponent(inner)}`
}

interface ForgeFileEditorProps {
  filename: string
  workspaceId: string
  workspacePath: string
  onClose: () => void
  width?: number
  closing?: boolean
}

export function ForgeFileEditor({
  filename,
  workspaceId,
  workspacePath,
  onClose,
  width = 520,
  closing = false,
}: ForgeFileEditorProps) {
  const { t } = useI18n()
  const [mode, setMode] = useState<EditorMode>('edit')
  const [content, setContent] = useState('')
  const [dirty, setDirty] = useState(false)
  const [loading, setLoading] = useState(true)
  const isInitialMount = useRef(true)
  const { wordWrap, toggleWordWrap } = useWordWrap()

  const kind = getFileKind(filename)
  const inner = toInnerPath(filename)
  const fileType = detectFileType(filename)
  const category = fileType.category

  // Determine if this file needs raw URL loading (media, pdf)
  const needsRawUrl: boolean =
    category === 'image' ||
    category === 'video' ||
    category === 'audio' ||
    category === 'pdf'

  // Determine if this file is editable in the code editor
  const isEditable = fileType.editable

  // Determine if this file has a dedicated preview (other than source view)
  const hasPreview = fileType.previewable

  const rawUrl = needsRawUrl ? buildRawUrl(workspaceId, filename, kind, inner) : ''

  // Build read URL for text content
  const readUrl =
    kind === 'sub-agent'
      ? `/api/workspaces/${workspaceId}/agents/${encodeURIComponent(inner.replace('agents/', ''))}`
      : kind === 'forge-config' || kind === 'forge-subdir'
        ? `/api/workspaces/${workspaceId}/files?name=${encodeURIComponent(inner)}`
        : `/api/workspaces/${workspaceId}/project-files?path=${encodeURIComponent(filename)}`

  // Absolute path for "Open externally" (Electron only)
  const absPath = `${workspacePath}/${filename}`

  const handleOpenExternal = useCallback(() => {
    const api = (window as unknown as { electronAPI?: { openPath?: (p: string) => Promise<string> } }).electronAPI
    if (api?.openPath) {
      api.openPath(absPath)
    }
  }, [absPath])

  useEffect(() => {
    setLoading(true)
    setDirty(false)
    setMode('edit')

    if (isInitialMount.current) {
      isInitialMount.current = false
    }

    // Media, PDF, and binary files don't need text content
    if (needsRawUrl || category === 'binary') {
      setContent('')
      setLoading(false)
      return
    }

    fetch(readUrl)
      .then((r) => (r.ok ? r.json() : { content: '' }))
      .then((data) => {
        setContent(data.content || '')
        setLoading(false)
      })
      .catch(() => {
        setContent('')
        setLoading(false)
      })
  }, [readUrl, needsRawUrl, category])

  const handleSave = useCallback(async () => {
    let url: string
    let body: string

    if (kind === 'sub-agent') {
      url = `/api/workspaces/${workspaceId}/agents/${encodeURIComponent(inner.replace('agents/', ''))}`
      body = JSON.stringify({ content })
    } else if (kind === 'forge-config' || kind === 'forge-subdir') {
      url = `/api/workspaces/${workspaceId}/files`
      body = JSON.stringify({ name: inner, content })
    } else {
      url = `/api/workspaces/${workspaceId}/project-files`
      body = JSON.stringify({ path: filename, content })
    }

    const res = await fetch(url, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body,
    })
    if (res.ok) setDirty(false)
  }, [filename, inner, content, workspaceId, kind])

  // Display name
  const displayName =
    kind === 'sub-agent'
      ? inner.replace('agents/', '')
      : kind === 'project'
        ? filename.split('/').pop() || filename
        : inner

  const filePath = `${workspacePath}/${filename}`

  /**
   * Render the preview content based on file category.
   */
  const renderPreview = () => {
    switch (category) {
      case 'html':
        return (
          <HtmlPreview
            content={content}
            filePath={filename}
            workspaceId={workspaceId}
            onOpenExternal={handleOpenExternal}
          />
        )
      case 'json':
        return <JsonPreview content={content} />
      case 'svg':
        return <SvgPreview content={content} fileName={displayName} />
      case 'markdown':
        return (
          <div className="h-full overflow-y-auto bg-page">
            <MarkdownPreview content={content} />
          </div>
        )
      default:
        // Fallback: try markdown preview for anything else (csv, text, etc.)
        return (
          <div className="h-full overflow-y-auto bg-page">
            <MarkdownPreview content={content} />
          </div>
        )
    }
  }

  /**
   * Render the main editor/view content area.
   */
  const renderContent = () => {
    if (loading) {
      return (
        <div className="flex items-center justify-center h-full text-muted text-[13px]">
          {t('status.loading')}
        </div>
      )
    }

    // ── Media files ──
    if (category === 'image') {
      return (
        <div className="flex items-center justify-center h-full bg-surface-2 p-4">
          <img
            src={rawUrl}
            alt={displayName}
            className="max-w-full max-h-full object-contain rounded-lg shadow-forge-md"
            draggable={false}
          />
        </div>
      )
    }

    if (category === 'video') {
      return <VideoPreview src={rawUrl} fileName={displayName} />
    }

    if (category === 'audio') {
      return <AudioPreview src={rawUrl} fileName={displayName} />
    }

    if (category === 'pdf') {
      return (
        <PdfPreview
          src={rawUrl}
          fileName={displayName}
          onOpenExternal={handleOpenExternal}
        />
      )
    }

    // ── Binary files ──
    if (category === 'binary') {
      return <BinaryPreview fileName={displayName} onOpenExternal={handleOpenExternal} />
    }

    // ── Editable files: edit / preview toggle ──
    if (mode === 'edit') {
      return (
        <CodeMirrorEditor
          value={content}
          onChange={(v) => {
            setContent(v)
            setDirty(true)
          }}
          language={getLanguageFromFilename(filename)}
          wordWrap={wordWrap}
        />
      )
    }

    return renderPreview()
  }

  return (
    <div
      className={cn(
        'flex flex-col h-full bg-page border-l border-subtle shrink-0 overflow-hidden sidebar-transition',
        isInitialMount.current && 'animate-expand-width'
      )}
      style={{ width, minWidth: closing ? 0 : 280 }}
      onKeyDown={(e) => {
        if ((e.metaKey || e.ctrlKey) && e.key === 's') {
          e.preventDefault()
          handleSave()
        }
      }}
    >
      {/* Header */}
      <div className="flex items-center h-[52px] px-4 shrink-0 border-b border-subtle gap-2 min-w-0">
        {/* Filename badge */}
        <div className="flex items-center gap-1.5 px-2 py-1 rounded-md bg-surface-active min-w-0 flex-1">
          <FileText size={14} className="text-indigo shrink-0" />
          <span className="text-[13px] font-semibold text-primary truncate">{displayName}</span>
        </div>

        {/* Save + Unsaved */}
        {dirty && (
          <button
            onClick={handleSave}
            className="flex items-center gap-1 px-2 py-1 rounded-md text-[12px] font-medium text-amber hover:bg-surface-hover transition-colors shrink-0"
          >
            <Save size={12} />
            <span>{t('button.save')}</span>
          </button>
        )}

        {/* Edit / Preview toggle — hidden for non-editable files */}
        {isEditable && hasPreview && (
          <div className="flex items-center shrink-0">
            {(['edit', 'preview'] as const).map((tab) => (
              <button
                key={tab}
                onClick={() => setMode(tab)}
                className={cn(
                  'px-2.5 py-1 text-[12px] font-medium transition-colors',
                  tab === 'edit' ? 'rounded-l-md' : 'rounded-r-md',
                  mode === tab
                    ? 'bg-surface-active text-primary'
                    : 'text-tertiary hover:text-secondary'
                )}
              >
                {tab === 'edit' ? 'Source' : 'Preview'}
              </button>
            ))}
          </div>
        )}

        {/* "Open externally" for binary/media files */}
        {!isEditable && (
          <button
            onClick={handleOpenExternal}
            className="flex items-center gap-1 px-2 py-1 rounded-md text-[12px] font-medium text-tertiary hover:bg-surface-hover transition-colors shrink-0"
            title="Open with default application"
          >
            <ExternalLink size={12} />
          </button>
        )}

        {/* Word Wrap toggle — hidden for non-editable files */}
        {isEditable && (
          <button
            onClick={toggleWordWrap}
            className={cn(
              'p-1.5 rounded-md hover:bg-surface-hover transition-colors shrink-0',
              wordWrap ? 'text-muted' : 'text-tertiary'
            )}
            title={wordWrap ? 'Word wrap: on' : 'Word wrap: off'}
          >
            <WrapText size={16} />
          </button>
        )}

        {/* Close button */}
        <button
          onClick={onClose}
          className="p-1.5 rounded-md hover:bg-surface-hover transition-colors shrink-0"
          title={t('button.closeEditor')}
        >
          <X size={16} className="text-tertiary" />
        </button>
      </div>

      {/* Sub-header: file path */}
      <div className="flex items-center h-7 px-4 border-b border-subtle bg-surface shrink-0">
        <Folder size={11} className="text-muted shrink-0" />
        <span className="text-[11px] text-muted ml-1.5 font-mono truncate">{filePath}</span>
      </div>

      {/* Editor Content */}
      <div className="flex-1 overflow-hidden">{renderContent()}</div>
    </div>
  )
}
