import { useMemo, useRef } from 'react'
import { Plus } from 'lucide-react'
import { Button, Input, Textarea, Tooltip } from '@/components/emcn'
import { Trash } from '@/components/emcn/icons/trash'
import { Label } from '@/components/ui/label'
import { cn } from '@/lib/core/utils/cn'
import { generateId } from '@/lib/core/utils/uuid'
import { formatDisplayText } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/formatted-text'
import { TagDropdown } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown'
import { useSubBlockInput } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-sub-block-input'
import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-sub-block-value'
import { useAccessibleReferencePrefixes } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-accessible-reference-prefixes'

interface EvalMetric {
  id: string
  name: string
  description: string
  range: {
    min: number
    max: number
  }
}

interface EvalInputProps {
  blockId: string
  subBlockId: string
  isPreview?: boolean
  previewValue?: EvalMetric[] | null
  disabled?: boolean
}

// Default values
const createDefaultMetric = (): EvalMetric => ({
  id: generateId(),
  name: '',
  description: '',
  range: { min: 0, max: 1 },
})

export function EvalInput({
  blockId,
  subBlockId,
  isPreview = false,
  previewValue,
  disabled = false,
}: EvalInputProps) {
  const [storeValue, setStoreValue] = useSubBlockValue<EvalMetric[]>(blockId, subBlockId)
  const accessiblePrefixes = useAccessibleReferencePrefixes(blockId)
  const descriptionInputRefs = useRef<Record<string, HTMLTextAreaElement>>({})
  const descriptionOverlayRefs = useRef<Record<string, HTMLDivElement>>({})

  // Use the extended hook for field-level management
  const inputController = useSubBlockInput({
    blockId,
    subBlockId,
    config: {
      id: subBlockId,
      type: 'eval-input',
      connectionDroppable: true,
    },
    isPreview,
    disabled,
  })

  const value = isPreview ? previewValue : storeValue

  const defaultMetric = useMemo(() => createDefaultMetric(), [])
  const metrics: EvalMetric[] = value || [defaultMetric]

  const addMetric = () => {
    if (isPreview || disabled) return

    const newMetric: EvalMetric = createDefaultMetric()
    setStoreValue([...metrics, newMetric])
  }

  const removeMetric = (id: string) => {
    if (isPreview || disabled || metrics.length === 1) return
    setStoreValue(metrics.filter((metric) => metric.id !== id))
  }

  const updateMetric = (id: string, field: keyof EvalMetric, value: any) => {
    if (isPreview || disabled) return
    setStoreValue(
      metrics.map((metric) => (metric.id === id ? { ...metric, [field]: value } : metric))
    )
  }

  const updateRange = (id: string, field: 'min' | 'max', value: string) => {
    if (isPreview || disabled) return
    setStoreValue(
      metrics.map((metric) =>
        metric.id === id
          ? {
              ...metric,
              range: {
                ...metric.range,
                [field]: value === '' ? undefined : Number.parseInt(value, 10),
              },
            }
          : metric
      )
    )
  }

  const handleRangeBlur = (id: string, field: 'min' | 'max', value: string) => {
    const sanitizedValue = value.replace(/[^\d.-]/g, '')
    const numValue = Number.parseFloat(sanitizedValue)

    setStoreValue(
      metrics.map((metric) =>
        metric.id === id
          ? {
              ...metric,
              range: {
                ...metric.range,
                [field]: !Number.isNaN(numValue) ? numValue : 0,
              },
            }
          : metric
      )
    )
  }

  // Helper to update a metric field
  const updateMetricField = (metricId: string, newDescription: string) => {
    updateMetric(metricId, 'description', newDescription)
  }

  const renderMetricHeader = (metric: EvalMetric, index: number) => (
    <div className='flex items-center justify-between overflow-hidden rounded-t-[4px] border-[var(--border-1)] border-b bg-[var(--surface-4)] px-2.5 py-[5px]'>
      <span className='font-medium text-[var(--text-tertiary)] text-sm'>Metric {index + 1}</span>
      <div className='flex items-center gap-2'>
        <Tooltip.Root key={`add-${metric.id}`}>
          <Tooltip.Trigger asChild>
            <Button
              variant='ghost'
              onClick={addMetric}
              disabled={isPreview || disabled}
              className='h-auto p-0'
            >
              <Plus className='h-[14px] w-[14px]' />
              <span className='sr-only'>Add Metric</span>
            </Button>
          </Tooltip.Trigger>
          <Tooltip.Content>Add Metric</Tooltip.Content>
        </Tooltip.Root>

        <Tooltip.Root key={`remove-${metric.id}`}>
          <Tooltip.Trigger asChild>
            <Button
              variant='ghost'
              onClick={() => removeMetric(metric.id)}
              disabled={isPreview || disabled || metrics.length === 1}
              className='h-auto p-0 text-[var(--text-error)] hover-hover:text-[var(--text-error)]'
            >
              <Trash className='h-[14px] w-[14px]' />
              <span className='sr-only'>Delete Metric</span>
            </Button>
          </Tooltip.Trigger>
          <Tooltip.Content>Delete Metric</Tooltip.Content>
        </Tooltip.Root>
      </div>
    </div>
  )

  return (
    <div className='space-y-2'>
      {metrics.map((metric, index) => (
        <div
          key={metric.id}
          data-metric-id={metric.id}
          className='group relative overflow-visible rounded-sm border border-[var(--border-1)]'
        >
          {renderMetricHeader(metric, index)}

          <div className='flex flex-col gap-2 border-[var(--border-1)] px-2.5 pt-1.5 pb-2.5'>
            <div key={`name-${metric.id}`} className='flex flex-col gap-1.5'>
              <Label className='text-small'>Name</Label>
              <Input
                name='name'
                value={metric.name}
                onChange={(e) => updateMetric(metric.id, 'name', e.target.value)}
                placeholder='Accuracy'
                disabled={isPreview || disabled}
              />
            </div>

            <div key={`description-${metric.id}`} className='flex flex-col gap-1.5'>
              <Label className='text-small'>Description</Label>
              <div className='relative'>
                {(() => {
                  const fieldState = inputController.fieldHelpers.getFieldState(metric.id)
                  const handlers = inputController.fieldHelpers.createFieldHandlers(
                    metric.id,
                    metric.description || '',
                    (newValue) => updateMetricField(metric.id, newValue)
                  )
                  const tagSelectHandler = inputController.fieldHelpers.createTagSelectHandler(
                    metric.id,
                    metric.description || '',
                    (newValue) => updateMetricField(metric.id, newValue)
                  )

                  return (
                    <>
                      <Textarea
                        ref={(el) => {
                          if (el) descriptionInputRefs.current[metric.id] = el
                        }}
                        value={metric.description}
                        onChange={handlers.onChange}
                        onKeyDown={handlers.onKeyDown}
                        onDrop={handlers.onDrop}
                        onDragOver={handlers.onDragOver}
                        onFocus={handlers.onFocus}
                        placeholder='How accurate is the response?'
                        disabled={isPreview || disabled}
                        className={cn(
                          'min-h-[80px] whitespace-pre-wrap text-transparent caret-foreground'
                        )}
                        rows={3}
                      />
                      <div
                        ref={(el) => {
                          if (el) descriptionOverlayRefs.current[metric.id] = el
                        }}
                        className={cn(
                          'absolute inset-0 overflow-auto bg-transparent px-2 py-2 font-medium font-sans text-[var(--code-foreground)] text-sm',
                          !(isPreview || disabled) && 'pointer-events-none'
                        )}
                      >
                        <div className='whitespace-pre-wrap'>
                          {formatDisplayText(metric.description || '', {
                            accessiblePrefixes,
                            highlightAll: !accessiblePrefixes,
                          })}
                        </div>
                      </div>
                      {fieldState.showTags && (
                        <TagDropdown
                          visible={fieldState.showTags}
                          onSelect={tagSelectHandler}
                          blockId={blockId}
                          activeSourceBlockId={fieldState.activeSourceBlockId}
                          inputValue={metric.description || ''}
                          cursorPosition={fieldState.cursorPosition}
                          onClose={() => inputController.fieldHelpers.hideFieldDropdowns(metric.id)}
                          inputRef={{
                            current: descriptionInputRefs.current[metric.id] || null,
                          }}
                        />
                      )}
                    </>
                  )
                })()}
              </div>
            </div>

            <div key={`range-${metric.id}`} className='grid grid-cols-2 gap-2'>
              <div className='flex flex-col gap-1.5'>
                <Label className='text-small'>Min Value</Label>
                <Input
                  type='text'
                  value={metric.range.min}
                  onChange={(e) => updateRange(metric.id, 'min', e.target.value)}
                  onBlur={(e) => handleRangeBlur(metric.id, 'min', e.target.value)}
                  disabled={isPreview || disabled}
                  autoComplete='off'
                  data-form-type='other'
                  name='eval-range-min'
                />
              </div>
              <div className='flex flex-col gap-1.5'>
                <Label className='text-small'>Max Value</Label>
                <Input
                  type='text'
                  value={metric.range.max}
                  onChange={(e) => updateRange(metric.id, 'max', e.target.value)}
                  onBlur={(e) => handleRangeBlur(metric.id, 'max', e.target.value)}
                  disabled={isPreview || disabled}
                  autoComplete='off'
                  data-form-type='other'
                  name='eval-range-max'
                />
              </div>
            </div>
          </div>
        </div>
      ))}
    </div>
  )
}
