'use client'

import { useCallback, useMemo, useState } from 'react'
import {
  ReactFlow,
  ReactFlowProvider,
  Background,
  Controls,
  MiniMap,
  addEdge,
  useNodesState,
  useEdgesState,
  useReactFlow,
  type Connection,
  type Node,
} from '@xyflow/react'
import '@xyflow/react/dist/style.css'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Switch } from '@/components/ui/switch'
import { Plus, Variable } from 'lucide-react'
import { workflowNodeTypes } from './workflow-nodes'
import { WorkflowTriggersPanel } from './workflow-triggers-panel'
import { WorkflowNodeInspector } from './workflow-node-inspector'
import { AutomationDomainProvider } from './automation-domain-context'
import {
  PALETTE_NODE_TYPES,
  NODE_TYPE_LABELS,
  NODE_TYPE_DESCRIPTIONS,
} from '@/lib/mail-automation/node-definitions'
import {
  createFlowNode,
  flowToWorkflow,
  workflowEdgesToFlow,
  workflowNodesToFlow,
} from '@/lib/mail-automation/workflow-flow'
import type { ApiRule } from '@/lib/api/types'
import type { ExecVariable, RuleEditorState, WorkflowNodeType } from '@/lib/mail-automation/types'
import { nextNodeId } from '@/lib/mail-automation/defaults'

interface RuleWorkflowEditorProps {
  state: RuleEditorState
  allRules: ApiRule[]
  onChange: (state: RuleEditorState) => void
  readOnly?: boolean
}

export function RuleWorkflowEditor(props: RuleWorkflowEditorProps) {
  return (
    <ReactFlowProvider>
      <RuleWorkflowEditorInner {...props} />
    </ReactFlowProvider>
  )
}

function RuleWorkflowEditorInner({
  state,
  allRules,
  onChange,
  readOnly,
}: RuleWorkflowEditorProps) {
  const { setCenter, getNodes } = useReactFlow()
  const initialNodes = useMemo(() => workflowNodesToFlow(state.workflow.nodes), [state.workflow.nodes])
  const initialEdges = useMemo(() => workflowEdgesToFlow(state.workflow.edges), [state.workflow.edges])

  const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes)
  const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges)
  const [selectedId, setSelectedId] = useState<string | null>(null)

  const selectedNode = nodes.find((n) => n.id === selectedId) ?? null

  const syncWorkflow = useCallback(
    (nextNodes: Node[], nextEdges: typeof edges) => {
      onChange({
        ...state,
        workflow: flowToWorkflow(
          state.rule_kind,
          state.workflow.triggers,
          state.workflow.variables,
          nextNodes,
          nextEdges
        ),
      })
    },
    [onChange, state]
  )

  const applySelection = useCallback(
    (nodeId: string | null) => {
      setSelectedId(nodeId)
      setNodes((nds) =>
        nds.map((n) => ({
          ...n,
          selected: nodeId !== null && n.id === nodeId,
        }))
      )
    },
    [setNodes]
  )

  const focusNode = useCallback(
    (nodeId: string) => {
      requestAnimationFrame(() => {
        const node = getNodes().find((n) => n.id === nodeId)
        if (!node) return
        const w = node.measured?.width ?? 200
        const h = node.measured?.height ?? 80
        setCenter(node.position.x + w / 2, node.position.y + h / 2, {
          zoom: 1,
          duration: 300,
        })
      })
    },
    [getNodes, setCenter]
  )

  const onConnect = useCallback(
    (connection: Connection) => {
      if (readOnly) return
      const next = addEdge({ ...connection, animated: true, id: nextNodeId('e') }, edges)
      setEdges(next)
      syncWorkflow(nodes, next)
    },
    [edges, nodes, readOnly, setEdges, syncWorkflow]
  )

  const onNodeDragStop = useCallback(() => {
    syncWorkflow(nodes, edges)
  }, [edges, nodes, syncWorkflow])

  function addNode(type: WorkflowNodeType) {
    if (readOnly || type === 'start' || type === 'end') return
    const last = nodes[nodes.length - 1]
    const x = last ? last.position.x + 220 : 300
    const y = last ? last.position.y : 200
    const node = createFlowNode(type, { x, y })
    const nextNodes = nodes.map((n) => ({ ...n, selected: false })).concat({ ...node, selected: true })
    setNodes(nextNodes)
    syncWorkflow(nextNodes, edges)
    applySelection(node.id)
    setTimeout(() => focusNode(node.id), 50)
  }

  function updateNodeData(nodeId: string, data: Record<string, unknown>) {
    const nextNodes = nodes.map((n) => (n.id === nodeId ? { ...n, data } : n))
    setNodes(nextNodes)
    syncWorkflow(nextNodes, edges)
  }

  function deleteNode(nodeId: string) {
    const node = nodes.find((n) => n.id === nodeId)
    if (!node || node.type === 'start' || node.type === 'end') return
    const nextNodes = nodes.filter((n) => n.id !== nodeId)
    const nextEdges = edges.filter((e) => e.source !== nodeId && e.target !== nodeId)
    setNodes(nextNodes)
    setEdges(nextEdges)
    syncWorkflow(nextNodes, nextEdges)
    applySelection(null)
  }

  function updateVariables(variables: ExecVariable[]) {
    onChange({
      ...state,
      workflow: { ...state.workflow, variables },
    })
  }

  return (
    <AutomationDomainProvider triggers={state.workflow.triggers}>
    <div className="flex min-h-[520px] flex-col gap-3 lg:flex-row">
      <aside className="w-full shrink-0 space-y-2 lg:w-52">
        <p className="text-xs font-medium text-muted-foreground">Ajouter un nœud</p>
        <div className="space-y-1">
          {PALETTE_NODE_TYPES.map((type) => (
            <Button
              key={type}
              type="button"
              variant="outline"
              size="sm"
              className="h-auto w-full min-w-0 justify-start px-2 py-1.5 text-left text-xs"
              disabled={readOnly}
              onClick={() => addNode(type)}
              title={NODE_TYPE_DESCRIPTIONS[type]}
            >
              <Plus className="mr-1.5 mt-0.5 size-3 shrink-0 self-start" />
              <span className="min-w-0 flex-1">
                <span className="block font-medium leading-tight">{NODE_TYPE_LABELS[type]}</span>
                <span className="mt-0.5 block text-wrap break-words text-[10px] leading-snug text-muted-foreground">
                  {NODE_TYPE_DESCRIPTIONS[type]}
                </span>
              </span>
            </Button>
          ))}
        </div>

        <VariablesPanel variables={state.workflow.variables} disabled={readOnly} onChange={updateVariables} />
      </aside>

      <div className="flex min-w-0 flex-1 flex-col gap-3">
        <div className="grid gap-2 sm:grid-cols-2 lg:grid-cols-4">
          <div>
            <Label className="text-xs">Nom</Label>
            <Input
              className="mt-1 h-8 text-xs"
              value={state.name}
              disabled={readOnly}
              onChange={(e) => onChange({ ...state, name: e.target.value })}
            />
          </div>
          <div>
            <Label className="text-xs">Priorité</Label>
            <Input
              type="number"
              className="mt-1 h-8 text-xs"
              value={state.priority}
              disabled={readOnly}
              onChange={(e) => onChange({ ...state, priority: Number(e.target.value) || 0 })}
            />
          </div>
          <div className="flex items-end gap-2 pb-1">
            <Switch
              checked={state.is_active}
              disabled={readOnly}
              onCheckedChange={(v) => onChange({ ...state, is_active: v })}
            />
            <Label className="text-xs">Active</Label>
          </div>
          <div>
            <Label className="text-xs">Type</Label>
            <Input className="mt-1 h-8 text-xs" value={state.rule_kind === 'function' ? 'Fonction' : 'Règle'} readOnly />
          </div>
        </div>

        {state.rule_kind === 'rule' ? (
          <WorkflowTriggersPanel
            triggers={state.workflow.triggers}
            disabled={readOnly}
            onChange={(triggers) =>
              onChange({ ...state, workflow: { ...state.workflow, triggers } })
            }
          />
        ) : null}

        <div className="h-[420px] overflow-hidden rounded-lg border border-border">
          <ReactFlow
            nodes={nodes}
            edges={edges}
            nodeTypes={workflowNodeTypes}
            onNodesChange={readOnly ? undefined : onNodesChange}
            onEdgesChange={readOnly ? undefined : onEdgesChange}
            onConnect={onConnect}
            onNodeDragStop={onNodeDragStop}
            onNodeClick={(_, n) => applySelection(n.id)}
            onPaneClick={() => applySelection(null)}
            fitView
            proOptions={{ hideAttribution: true }}
          >
            <Background gap={16} />
            <Controls showInteractive={!readOnly} />
            <MiniMap pannable zoomable />
          </ReactFlow>
        </div>
      </div>

      <aside className="w-full shrink-0 overflow-hidden rounded-lg border border-border lg:w-64">
        <WorkflowNodeInspector
          node={selectedNode}
          allRules={allRules}
          triggers={state.workflow.triggers}
          onUpdate={updateNodeData}
          onDelete={deleteNode}
        />
      </aside>
    </div>
    </AutomationDomainProvider>
  )
}

function VariablesPanel({
  variables,
  onChange,
  disabled,
}: {
  variables: ExecVariable[]
  onChange: (v: ExecVariable[]) => void
  disabled?: boolean
}) {
  return (
    <div className="mt-4 space-y-2 rounded-lg border border-border/60 p-2">
      <div className="flex items-center gap-1 text-xs font-medium">
        <Variable className="size-3.5" />
        Variables d&apos;exécution
      </div>
      {variables.map((v, i) => (
        <div key={i} className="flex gap-1">
          <Input
            className="h-7 flex-1 font-mono text-[10px]"
            placeholder="nom"
            value={v.name}
            disabled={disabled}
            onChange={(e) => {
              const next = [...variables]
              next[i] = { ...v, name: e.target.value }
              onChange(next)
            }}
          />
          <Input
            className="h-7 flex-1 text-[10px]"
            placeholder="défaut"
            value={v.default ?? ''}
            disabled={disabled}
            onChange={(e) => {
              const next = [...variables]
              next[i] = { ...v, default: e.target.value }
              onChange(next)
            }}
          />
        </div>
      ))}
      <Button
        type="button"
        variant="ghost"
        size="sm"
        className="h-7 w-full text-xs"
        disabled={disabled}
        onClick={() => onChange([...variables, { name: '', type: 'string', default: '' }])}
      >
        <Plus className="mr-1 size-3" />
        Variable
      </Button>
    </div>
  )
}
