'use client'

import { useCallback, useMemo, useState } from 'react'
import Combobox from '@/components/editor/Combobox'
import type { ComboboxItem } from '@/components/editor/Combobox'
import { useEditorContext } from '@/components/editor/EditorContext'
import type { Condition } from '@/types/flowchart'

type ConditionEditorProps = {
  edgeId: string
  condition: Condition | undefined
  onChange: (edgeId: string, condition: Condition | undefined) => void
  onClose: () => void
}

export default function ConditionEditor({
  edgeId,
  condition,
  onChange,
  onClose,
}: ConditionEditorProps) {
  const { variables, onAddVariable } = useEditorContext()

  const [showAddForm, setShowAddForm] = useState(false)
  const [newName, setNewName] = useState('')
  const [newType, setNewType] = useState<'numeric' | 'string' | 'boolean'>('numeric')

  const variableItems: ComboboxItem[] = useMemo(
    () =>
      variables.map((v) => ({
        id: v.id,
        label: v.name,
        badge: v.type,
      })),
    [variables]
  )

  const selectedVariable = useMemo(() => {
    if (!condition?.variableId) return undefined
    return variables.find((v) => v.id === condition.variableId)
  }, [condition?.variableId, variables])

  const hasInvalidReference = useMemo(() => {
    if (!condition?.variableId) return false
    return !variables.some((v) => v.id === condition.variableId)
  }, [condition?.variableId, variables])

  // Determine operators based on variable type
  const availableOperators = useMemo(() => {
    if (!selectedVariable || selectedVariable.type === 'numeric') {
      return [
        { value: '==', label: '==' },
        { value: '!=', label: '!=' },
        { value: '>', label: '>' },
        { value: '<', label: '<' },
        { value: '>=', label: '>=' },
        { value: '<=', label: '<=' },
      ] as const
    }
    // string and boolean only support == and !=
    return [
      { value: '==', label: '==' },
      { value: '!=', label: '!=' },
    ] as const
  }, [selectedVariable])

  const handleVariableSelect = useCallback(
    (variableId: string) => {
      const variable = variables.find((v) => v.id === variableId)
      const defaultValue = variable
        ? variable.type === 'numeric'
          ? 0
          : variable.type === 'boolean'
            ? false
            : ''
        : 0
      // Reset operator if current one is not valid for new type
      const validOperator =
        variable && variable.type !== 'numeric' && condition?.operator && !['==', '!='].includes(condition.operator)
          ? '=='
          : condition?.operator || '=='

      onChange(edgeId, {
        variableName: variable?.name || '',
        variableId,
        operator: validOperator as Condition['operator'],
        value: defaultValue,
      })
    },
    [variables, condition?.operator, edgeId, onChange]
  )

  const handleOperatorChange = useCallback(
    (operator: string) => {
      if (!condition) return
      onChange(edgeId, {
        ...condition,
        operator: operator as Condition['operator'],
      })
    },
    [condition, edgeId, onChange]
  )

  const handleValueChange = useCallback(
    (value: number | string | boolean) => {
      if (!condition) return
      onChange(edgeId, {
        ...condition,
        value,
      })
    },
    [condition, edgeId, onChange]
  )

  const handleRemoveCondition = useCallback(() => {
    onChange(edgeId, undefined)
    onClose()
  }, [edgeId, onChange, onClose])

  const handleAddNew = useCallback(() => {
    setShowAddForm(true)
    setNewName('')
    setNewType('numeric')
  }, [])

  const handleSubmitNew = useCallback(() => {
    if (!newName.trim()) return
    const defaultValue = newType === 'numeric' ? 0 : newType === 'boolean' ? false : ''
    const newId = onAddVariable(newName.trim(), newType, defaultValue)
    onChange(edgeId, {
      variableName: newName.trim(),
      variableId: newId,
      operator: '==',
      value: defaultValue,
    })
    setShowAddForm(false)
  }, [newName, newType, onAddVariable, edgeId, onChange])

  const handleCancelNew = useCallback(() => {
    setShowAddForm(false)
  }, [])

  // Render value input based on variable type
  const renderValueInput = () => {
    const varType = selectedVariable?.type || 'numeric'

    if (varType === 'boolean') {
      return (
        <select
          value={String(condition?.value ?? false)}
          onChange={(e) => handleValueChange(e.target.value === 'true')}
          className="w-full rounded border border-zinc-300 bg-white px-2 py-1 text-sm focus:border-blue-500 focus:outline-none dark:border-zinc-600 dark:bg-zinc-700 dark:text-white"
        >
          <option value="true">true</option>
          <option value="false">false</option>
        </select>
      )
    }

    if (varType === 'string') {
      return (
        <input
          type="text"
          value={String(condition?.value ?? '')}
          onChange={(e) => handleValueChange(e.target.value)}
          placeholder="Value..."
          className="w-full rounded border border-zinc-300 bg-white px-2 py-1 text-sm focus:border-blue-500 focus:outline-none dark:border-zinc-600 dark:bg-zinc-700 dark:text-white dark:placeholder-zinc-400"
        />
      )
    }

    // numeric
    return (
      <input
        type="number"
        value={typeof condition?.value === 'number' ? condition.value : 0}
        onChange={(e) => handleValueChange(parseFloat(e.target.value) || 0)}
        className="w-full rounded border border-zinc-300 bg-white px-2 py-1 text-sm focus:border-blue-500 focus:outline-none dark:border-zinc-600 dark:bg-zinc-700 dark:text-white"
      />
    )
  }

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center">
      <div className="absolute inset-0 bg-black/40" onClick={onClose} />
      <div className="relative w-full max-w-sm rounded-lg border border-zinc-200 bg-white p-4 shadow-xl dark:border-zinc-700 dark:bg-zinc-800">
        <div className="mb-3 flex items-center justify-between">
          <h3 className="text-sm font-semibold text-zinc-800 dark:text-zinc-100">
            Edge Condition
          </h3>
          <button
            onClick={onClose}
            className="rounded p-0.5 text-zinc-400 hover:bg-zinc-100 hover:text-zinc-600 dark:hover:bg-zinc-700 dark:hover:text-zinc-300"
          >
            <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
            </svg>
          </button>
        </div>

        {/* Variable selector */}
        <div className="mb-3">
          <label className="mb-1 block text-xs font-medium text-zinc-600 dark:text-zinc-300">
            Variable
          </label>
          <div className={hasInvalidReference ? 'rounded ring-2 ring-orange-500' : ''}>
            <Combobox
              items={variableItems}
              value={condition?.variableId}
              onChange={handleVariableSelect}
              placeholder="Select variable..."
              onAddNew={handleAddNew}
            />
          </div>
          {hasInvalidReference && (
            <div className="mt-1 text-xs text-orange-600 dark:text-orange-400">
              Variable not found
            </div>
          )}
        </div>

        {/* Inline add form */}
        {showAddForm && (
          <div className="mb-3 rounded border border-zinc-300 bg-zinc-50 p-2 dark:border-zinc-600 dark:bg-zinc-900">
            <div className="mb-1 text-xs font-medium text-zinc-600 dark:text-zinc-300">
              New variable
            </div>
            <div className="flex items-center gap-1.5">
              <input
                type="text"
                value={newName}
                onChange={(e) => setNewName(e.target.value)}
                placeholder="Name"
                className="w-full rounded border border-zinc-300 bg-white px-2 py-0.5 text-sm focus:border-blue-500 focus:outline-none dark:border-zinc-600 dark:bg-zinc-700 dark:text-white dark:placeholder-zinc-400"
                onKeyDown={(e) => {
                  if (e.key === 'Enter') handleSubmitNew()
                  if (e.key === 'Escape') handleCancelNew()
                }}
                autoFocus
              />
            </div>
            <div className="mt-1.5 flex items-center gap-1.5">
              <select
                value={newType}
                onChange={(e) => setNewType(e.target.value as 'numeric' | 'string' | 'boolean')}
                className="rounded border border-zinc-300 bg-white px-2 py-0.5 text-sm focus:border-blue-500 focus:outline-none dark:border-zinc-600 dark:bg-zinc-700 dark:text-white"
              >
                <option value="numeric">numeric</option>
                <option value="string">string</option>
                <option value="boolean">boolean</option>
              </select>
            </div>
            <div className="mt-1.5 flex justify-end gap-1">
              <button
                onClick={handleCancelNew}
                className="rounded px-2 py-0.5 text-xs text-zinc-500 hover:bg-zinc-100 dark:text-zinc-400 dark:hover:bg-zinc-700"
              >
                Cancel
              </button>
              <button
                onClick={handleSubmitNew}
                disabled={!newName.trim()}
                className="rounded bg-blue-600 px-2 py-0.5 text-xs text-white hover:bg-blue-700 disabled:opacity-50"
              >
                Add
              </button>
            </div>
          </div>
        )}

        {/* Operator and value (shown when variable is selected) */}
        {condition?.variableId && (
          <>
            <div className="mb-3">
              <label className="mb-1 block text-xs font-medium text-zinc-600 dark:text-zinc-300">
                Operator
              </label>
              <select
                value={condition.operator || '=='}
                onChange={(e) => handleOperatorChange(e.target.value)}
                className="w-full rounded border border-zinc-300 bg-white px-2 py-1 text-sm focus:border-blue-500 focus:outline-none dark:border-zinc-600 dark:bg-zinc-700 dark:text-white"
              >
                {availableOperators.map((op) => (
                  <option key={op.value} value={op.value}>
                    {op.label}
                  </option>
                ))}
              </select>
            </div>

            <div className="mb-3">
              <label className="mb-1 block text-xs font-medium text-zinc-600 dark:text-zinc-300">
                Value
              </label>
              {renderValueInput()}
            </div>
          </>
        )}

        {/* Actions */}
        <div className="flex justify-between">
          {condition?.variableId ? (
            <button
              onClick={handleRemoveCondition}
              className="rounded px-2 py-1 text-xs text-red-600 hover:bg-red-50 dark:text-red-400 dark:hover:bg-red-900/20"
            >
              Remove condition
            </button>
          ) : (
            <div />
          )}
          <button
            onClick={onClose}
            className="rounded bg-blue-600 px-3 py-1 text-xs text-white hover:bg-blue-700"
          >
            Done
          </button>
        </div>
      </div>
    </div>
  )
}
