import React, { memo, useCallback, useContext } from 'react'
import FlowContext from '../../lib/flowContext'
import { nodePropsAreEqual } from '../../lib/flowUtils'
import {
    BaseNode,
    BaseNodeContent,
    BaseNodeFooter,
    BaseNodeHeaderRow,
} from './BaseNode'
import { NodeMenubar } from './NodeMenubar'
import { Input } from '../ui/input'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select'
import { Switch } from '../ui/switch'
import { NodeFooterEdgeIndicators } from './NodeFooterEdgeIndicators'
import { NodeHeaderTitle } from './NodeHeaderTitle'
import { OutputHandle } from './NodeHandles'
import { Variable } from 'lucide-react'

type ValueType = 'string' | 'number' | 'boolean'

type Props = {
    id: string
    data: {
        value?: string | number | boolean
        valueType?: ValueType
    }
}

const DEFAULT_BY_TYPE: Record<ValueType, string | number | boolean> = {
    string: '',
    number: 0,
    boolean: false,
}

function coerceValue(raw: string, valueType: ValueType): string | number | boolean {
    switch (valueType) {
        case 'number': {
            const n = Number(raw)
            return Number.isNaN(n) ? 0 : n
        }
        case 'boolean':
            return /^(1|true|yes|on)$/i.test(raw.trim())
        default:
            return raw
    }
}

export const VariableNode = memo(function VariableNode({ id, data }: Props) {
    const ctx = useContext(FlowContext)
    const setNodes = ctx?.setNodes

    const valueType: ValueType = data?.valueType ?? 'string'
    const value = data?.value ?? DEFAULT_BY_TYPE[valueType]
    const displayValue = typeof value === 'string' ? value : String(value)

    const updateData = useCallback(
        (updates: { value?: string | number | boolean; valueType?: ValueType }) => {
            if (!setNodes) return
            setNodes((nds: any[]) =>
                nds.map((n) =>
                    n.id === id ? { ...n, data: { ...n.data, ...updates } } : n
                )
            )
        },
        [id, setNodes]
    )

    const onTypeChange = useCallback(
        (nextType: string) => {
            const type = nextType as ValueType
            const raw = typeof value === 'boolean' ? (value ? 'true' : 'false') : String(value)
            const nextValue = coerceValue(raw, type)
            updateData({ valueType: type, value: nextValue })
        },
        [value, updateData]
    )

    const onValueChange = useCallback(
        (e: React.ChangeEvent<HTMLInputElement>) => {
            const raw = e.target.value
            const nextValue = coerceValue(raw, valueType)
            updateData({ value: nextValue })
        },
        [valueType, updateData]
    )

    const onBooleanChange = useCallback(
        (checked: boolean) => {
            updateData({ value: checked })
        },
        [updateData]
    )

    return (
        <BaseNode className="min-w-56 min-h-[180px]" handles={<OutputHandle id="out" />}>
            <BaseNodeHeaderRow icon={<Variable className="size-4" />} title={<NodeHeaderTitle nodeId={id} displayTitle={id} />} />

            <BaseNodeContent>
                <div className="shrink-0 w-full">
                    <NodeMenubar nodeId={id} nodeType="variable" />
                </div>
                <div className="flex flex-col p-2 gap-2">
                    <div className="flex flex-col gap-1.5">
                        <label className="text-xs font-medium text-muted-foreground">Type</label>
                        <Select value={valueType} onValueChange={onTypeChange}>
                            <SelectTrigger>
                                <SelectValue placeholder="Type" />
                            </SelectTrigger>
                            <SelectContent>
                                <SelectItem value="string">String</SelectItem>
                                <SelectItem value="number">Number</SelectItem>
                                <SelectItem value="boolean">Boolean</SelectItem>
                            </SelectContent>
                        </Select>
                    </div>
                    <div className="flex flex-col gap-1.5">
                        <label className="text-xs font-medium text-muted-foreground">Value</label>
                        {valueType === 'boolean' ? (
                            <div className="flex items-center gap-2 text-sm">
                                <Switch
                                    checked={value === true}
                                    onCheckedChange={onBooleanChange}
                                />
                                <span className="text-muted-foreground">{value ? 'true' : 'false'}</span>
                            </div>
                        ) : (
                            <Input
                                type={valueType === 'number' ? 'number' : 'text'}
                                value={valueType === 'number' ? (value as number) : displayValue}
                                onChange={onValueChange}
                            />
                        )}
                    </div>
                </div>
            </BaseNodeContent>

            <BaseNodeFooter>
                <NodeFooterEdgeIndicators nodeId={id} nodeType="variable">
                    {`${valueType.charAt(0).toUpperCase() + valueType.slice(1)} · ${displayValue.length ? `${displayValue.length} chars` : 'none'}`}
                </NodeFooterEdgeIndicators>
            </BaseNodeFooter>
        </BaseNode>
    )
}, nodePropsAreEqual)

VariableNode.displayName = 'VariableNode'

export default VariableNode
