import {DeleteFilled, EditFilled, FolderFilled, PlusCircleFilled, SaveFilled} from '@ant-design/icons'
import {
  addEdge,
  applyEdgeChanges,
  applyNodeChanges,
  Background,
  BackgroundVariant,
  Controls,
  type Edge,
  Handle,
  MiniMap,
  type Node,
  type NodeProps,
  type OnConnect,
  type OnEdgesChange,
  type OnNodesChange,
  Position,
  ReactFlow,
} from '@xyflow/react'
import {useMount} from 'ahooks'
import type {Schema} from 'amis'
import {Button, Card, Drawer, Dropdown, message, Space} from 'antd'
import {arrToMap, filter, find, findIdx, isEqual, isNil, randomId} from 'licia'
import {type JSX, useState} from 'react'
import styled from 'styled-components'
import '@xyflow/react/dist/style.css'
import {create} from 'zustand/react'
import {amisRender, commonInfo} from '../util/amis.tsx'

const FlowableDiv = styled.div`
    height: 93vh;

    .toolbar {
        z-index: 999;
        position: absolute;
    }
`

type AmisNodeType = 'normal' | 'start' | 'end'

const AmisNode = (
  props: NodeProps,
  type: AmisNodeType,
  name: String,
  description?: String,
  columnSchema?: Schema[],
) => {
  const {id, data} = props
  const {removeNode, editNode} = data
  return (
    <div className="p-1 w-64">
      <Card
        title={name}
        size="small"
        hoverable
      >
        <Dropdown
          trigger={['contextMenu']}
          menu={{
            items: [
              {
                key: 'edit',
                label: '编辑',
                icon: <EditFilled className="text-gray-600 hover:text-blue-500"/>,
              },
              {
                key: 'remove',
                label: '删除',
                icon: <DeleteFilled className="text-red-500 hover:text-red-500"/>,
              },
            ],
            onClick: menu => {
              switch (menu.key) {
                case 'edit':
                  // @ts-ignore
                  editNode(id, name, description, columnSchema)
                  break
                case 'remove':
                  // @ts-ignore
                  removeNode(id)
                  break
              }
            }
          }}
        >
          <div className="card-description p-2 text-secondary text-sm">
            {description}
          </div>
        </Dropdown>
      </Card>
      {isEqual(type, 'start') || isEqual(type, 'normal')
        ? <Handle type="source" position={Position.Right}/> : undefined}
      {isEqual(type, 'end') || isEqual(type, 'normal')
        ? <Handle type="target" position={Position.Left}/> : undefined}
    </div>
  )
}

const StartAmisNode = (props: NodeProps) => AmisNode(
  props,
  'start',
  '开始节点',
  '定义输入变量',
  [
    {
      type: 'input-kvs',
      name: 'fields',
      addButtonText: '新增入参',
      draggable: false,
      keyItem: {
        label: '参数名称',
      },
      valueItems: [
        {
          type: 'input-text',
          name: 'description',
          label: '参数描述',
        },
        {
          type: 'select',
          name: 'type',
          label: '参数类型',
          required: true,
          selectFirst: true,
          options: [
            {
              label: '文本',
              value: 'text',
            },
            {
              label: '数字',
              value: 'number',
            },
            {
              label: '文件',
              value: 'files',
            },
          ],
        },
      ],
    },
  ],
)
const EndAmisNode = (props: NodeProps) => AmisNode(
  props,
  'end',
  '结束节点',
  '定义输出变量',
  [
    {
      type: 'input-kvs',
      name: 'fields',
      addButtonText: '新增输出',
      draggable: false,
      keyItem: {
        label: '参数名称',
      },
      valueItems: [
        {
          type: 'select',
          name: 'type',
          label: '参数',
          required: true,
          selectFirst: true,
          options: [],
        },
      ],
    },
  ],
)
const LlmAmisNode = (props: NodeProps) => AmisNode(
  props,
  'normal',
  '大模型节点',
  '使用大模型对话',
  [
    {
      type: 'select',
      name: 'model',
      label: '大模型',
      required: true,
      selectFirst: true,
      options: [
        {
          label: 'Qwen3',
          value: 'qwen3',
        },
        {
          label: 'Deepseek',
          value: 'deepseek',
        },
      ],
    },
    {
      type: 'textarea',
      name: 'systemPrompt',
      label: '系统提示词',
      required: true,
    },
  ],
)

const initialNodes: Node[] = [
  {
    id: 'BMFP3Eov94',
    type: 'start-amis-node',
    position: {x: 10, y: 100},
    data: {},
  },
  {
    id: 'PYK8LjduQ1',
    type: 'end-amis-node',
    position: {x: 500, y: 100},
    data: {},
  },
]
const initialEdges: Edge[] = []

const useStore = create<{
  data: Record<string, any>,
  getData: () => Record<string, any>,
  setData: (data: Record<string, any>) => void,
  getDataById: (id: string) => any,
  setDataById: (id: string, data: any) => void,
}>((set, get) => ({
  data: {},
  getData: () => get().data,
  setData: (data) => set(data),
  getDataById: id => get().data[id],
  setDataById: (id, data) => {
    let updateData = get().data
    updateData[id] = data
    set({
      data: updateData,
    })
  },
}))

const useFlowStore = create<{
  nodes: Node[],
  onNodesChange: OnNodesChange,
  addNode: (node: Node) => void,
  removeNode: (id: string) => void,
  setNodes: (nodes: Node[]) => void,

  edges: Edge[],
  onEdgesChange: OnEdgesChange,
  setEdges: (edges: Edge[]) => void,

  onConnect: OnConnect,
}>((set, get) => ({
  nodes: [],
  onNodesChange: changes => {
    set({
      nodes: applyNodeChanges(changes, get().nodes),
    })
  },
  addNode: node => set({nodes: get().nodes.concat(node)}),
  removeNode: id => {
    set({
      nodes: filter(get().nodes, node => !isEqual(node.id, id))
    })
  },
  setNodes: nodes => set({nodes}),

  edges: [],
  onEdgesChange: changes => {
    set({
      edges: applyEdgeChanges(changes, get().edges),
    })
  },
  setEdges: edges => set({edges}),

  onConnect: connection => {
    set({
      edges: addEdge(connection, get().edges),
    })
  },
}))

function Test() {
  const [messageApi, contextHolder] = message.useMessage()
  const [nodeDef] = useState<{
    key: string,
    name: string,
    component: (props: NodeProps) => JSX.Element
  }[]>([
    {
      key: 'start-amis-node',
      name: '开始',
      component: StartAmisNode,
    },
    {
      key: 'end-amis-node',
      name: '结束',
      component: EndAmisNode,
    },
    {
      key: 'llm-amis-node',
      name: '大模型',
      component: LlmAmisNode,
    },
  ])
  const [open, setOpen] = useState(false)
  const onClose = () => setOpen(false)

  const {getData, getDataById, setDataById} = useStore()
  const {
    nodes,
    addNode,
    removeNode,
    setNodes,
    onNodesChange,
    edges,
    setEdges,
    onEdgesChange,
    onConnect,
  } = useFlowStore()

  const [currentNodeForm, setCurrentNodeForm] = useState<JSX.Element>()
  const editNode = (id: string, name: string, description: string, columnSchema?: Schema[]) => {
    if (!isNil(columnSchema)) {
      setCurrentNodeForm(
        amisRender(
          {
            debug: commonInfo.debug,
            title: name,
            type: 'form',
            wrapWithPanel: false,
            onEvent: {
              change: {
                actions: [
                  {
                    actionType: 'custom',
                    // @ts-ignore
                    script: (context, action, event) => {
                      console.log(id, context.props.data)
                      setDataById(id, context.props.data)
                    },
                  }
                ]
              }
            },
            body: columnSchema,
          },
          getDataById(id),
        )
      )
      setOpen(true)
    }
  }

  useMount(() => {
    for (let node of initialNodes) {
      node.data = {
        getDataById,
        setDataById,
        removeNode,
        editNode,
      }
    }
    setNodes(initialNodes)
    setEdges(initialEdges)
  })

  return (
    <FlowableDiv>
      {contextHolder}
      <Space className="toolbar">
        <Button type="primary" onClick={() => console.log(JSON.stringify(getData()))}>
          <SaveFilled/>
          保存
        </Button>
        <Dropdown
          menu={{
            items: nodeDef.map(def => ({key: def.key, label: def.name})),
            onClick: ({key}) => {
              if (isEqual(key, 'start-amis-node') && findIdx(nodes, (node: Node) => isEqual(key, node.type)) > -1) {
                messageApi.error('只能存在1个开始节点')
                return
              }
              if (isEqual(key, 'end-amis-node') && findIdx(nodes, (node: Node) => isEqual(key, node.type)) > -1) {
                messageApi.error('只能存在1个结束节点')
                return
              }

              addNode({
                id: randomId(10),
                type: key,
                position: {x: 100, y: 100},
                data: {
                  getDataById,
                  setDataById,
                  removeNode,
                  editNode,
                },
              })
            },
          }}
        >
          <Button type="dashed">
            <PlusCircleFilled/>
            新增节点
          </Button>
        </Dropdown>
      </Space>
      <Drawer
        title="节点编辑"
        open={open}
        onClose={onClose}
        destroyOnHidden
      >
        {currentNodeForm}
      </Drawer>
      <ReactFlow
        nodes={nodes}
        edges={edges}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        onConnect={onConnect}
        // @ts-ignore
        nodeTypes={arrToMap(
          nodeDef.map(def => def.key),
          key => find(nodeDef, def => isEqual(key, def.key))!.component)
        }
      >
        <Controls/>
        <MiniMap/>
        <Background variant={BackgroundVariant.Cross} gap={20} size={3}/>
      </ReactFlow>
    </FlowableDiv>
  )
}

export default Test