'use client'

import { useCallback, useState } from 'react'
import {
  ReactFlow,
  Controls,
  MiniMap,
  Background,
  useNodesState,
  useEdgesState,
  addEdge,
  type Connection,
  type Node,
  BackgroundVariant,
} from '@xyflow/react'
import '@xyflow/react/dist/style.css'

import SourceNode from './nodes/SourceNode'
import PipeNode from './nodes/PipeNode'
import SinkNode from './nodes/SinkNode'
import AnimatedPipeEdge from './edges/AnimatedPipeEdge'
import FlowToolbar from './FlowToolbar'
import { presets } from './presets'

const nodeTypes = {
  source: SourceNode,
  pipe: PipeNode,
  sink: SinkNode,
}

const edgeTypes = {
  animatedPipe: AnimatedPipeEdge,
}

export default function FlowCanvas() {
  const defaultPreset = typeof window !== 'undefined' && window.innerWidth < 768 ? 0 : 0
  const [nodes, setNodes, onNodesChange] = useNodesState(presets[defaultPreset].nodes)
  const [edges, setEdges, onEdgesChange] = useEdgesState(presets[defaultPreset].edges)
  const [isPlaying, setIsPlaying] = useState(true)
  const [nodeIdCounter, setNodeIdCounter] = useState(100)

  const onConnect = useCallback(
    (connection: Connection) => {
      setEdges((eds) =>
        addEdge(
          { ...connection, type: 'animatedPipe', data: { flowRate: 3 } },
          eds
        )
      )
    },
    [setEdges]
  )

  const handleAddNode = useCallback(
    (type: 'source' | 'pipe' | 'sink') => {
      const id = `n${nodeIdCounter}`
      setNodeIdCounter((c) => c + 1)

      const labels = { source: 'Source', pipe: 'Pipe', sink: 'Sink' }
      const newNode: Node = {
        id,
        type,
        position: { x: 200 + Math.random() * 200, y: 100 + Math.random() * 200 },
        data: {
          label: labels[type],
          ...(type === 'source' ? { flowRate: 5 } : {}),
          ...(type === 'sink' ? { fillLevel: 0 } : {}),
        },
      }
      setNodes((nds) => [...nds, newNode])
    },
    [nodeIdCounter, setNodes]
  )

  const handleLoadPreset = useCallback(
    (index: number) => {
      const preset = presets[index]
      setNodes(preset.nodes)
      setEdges(preset.edges)
    },
    [setNodes, setEdges]
  )

  const handleReset = useCallback(() => {
    setNodes(presets[2].nodes)
    setEdges(presets[2].edges)
  }, [setNodes, setEdges])

  const showMiniMap = typeof window !== 'undefined' && window.innerWidth >= 768

  return (
    <div className="w-full h-[500px] md:h-[600px] rounded-2xl border border-flow/10 overflow-hidden relative bg-deep">
      <FlowToolbar
        onAddNode={handleAddNode}
        onLoadPreset={handleLoadPreset}
        onReset={handleReset}
        isPlaying={isPlaying}
        onTogglePlay={() => setIsPlaying(!isPlaying)}
      />
      <ReactFlow
        nodes={nodes}
        edges={edges}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        onConnect={onConnect}
        nodeTypes={nodeTypes}
        edgeTypes={edgeTypes}
        defaultEdgeOptions={{ type: 'animatedPipe' }}
        fitView
      >
        <Background variant={BackgroundVariant.Dots} gap={24} size={1} color="#2dd4bf08" />
        <Controls position="bottom-right" />
        {showMiniMap && (
          <MiniMap
            position="bottom-left"
            nodeColor="#2dd4bf30"
            maskColor="#050d1acc"
          />
        )}
      </ReactFlow>
    </div>
  )
}
