import PropTypes from 'prop-types'
import { Tree, Typography, Space, Tag } from 'antd'
import { useState, useMemo, useCallback } from 'react'
import XMarkIcon from '../../Icons/XMarkIcon'
import QuestionCircleIcon from '../../Icons/QuestionCircleIcon'
import JsonStringIcon from '../../Icons/JsonStringIcon'
import JsonArrayIcon from '../../Icons/JsonArrayIcon'
import JsonObjectIcon from '../../Icons/JsonObjectIcon'
import JsonBoolIcon from '../../Icons/JsonBoolIcon'
import JsonNumberIcon from '../../Icons/JsonNumberIcon'
import CopyButton from './CopyButton'

const { Text } = Typography

const DataTree = ({
  data,
  showLine = true,
  showValueCopy = true,
  showKeyCopy = false,
  defaultExpandAll = false,
  onNodeSelect,
  style = {}
}) => {
  const [expandedKeys, setExpandedKeys] = useState([])
  const [selectedKeys, setSelectedKeys] = useState([])

  // Function to get data type and format value
  const getDataTypeInfo = (value) => {
    if (value === null)
      return { type: 'null', color: 'default', icon: <XMarkIcon /> }
    if (value === undefined)
      return {
        type: 'undefined',
        color: 'default',
        icon: <QuestionCircleIcon />
      }
    if (typeof value === 'boolean')
      return { type: 'boolean', color: 'blue', icon: <JsonBoolIcon /> }
    if (typeof value === 'number')
      return { type: 'number', color: 'green', icon: <JsonNumberIcon /> }
    if (typeof value === 'string')
      return { type: 'string', color: 'orange', icon: <JsonStringIcon /> }
    if (Array.isArray(value))
      return { type: 'array', color: 'purple', icon: <JsonArrayIcon /> }
    if (typeof value === 'object')
      return { type: 'object', color: 'cyan', icon: <JsonObjectIcon /> }
    return { type: 'unknown', color: 'default', icon: <QuestionCircleIcon /> }
  }

  // Function to format value for display
  const formatValue = useCallback((value) => {
    if (value === null) return 'null'
    if (value === undefined) return 'undefined'
    if (typeof value === 'boolean') return value.toString()
    if (typeof value === 'number') return value.toString()
    if (typeof value === 'string') {
      // Truncate long strings
      return value.length > 50 ? `${value.substring(0, 50)}...` : value
    }
    if (Array.isArray(value)) return `Array (${value.length} items)`
    if (typeof value === 'object') {
      const keys = Object.keys(value)
      return `Object (${keys.length} properties)`
    }
    return String(value)
  }, [])

  // Function to get raw value for copying
  const getCopyValue = useCallback((value) => {
    if (value === null) return 'null'
    if (value === undefined) return 'undefined'
    if (typeof value === 'boolean') return value.toString()
    if (typeof value === 'number') return value.toString()
    if (typeof value === 'string') return value
    if (Array.isArray(value)) return JSON.stringify(value, null, 2)
    if (typeof value === 'object') return JSON.stringify(value, null, 2)
    return String(value)
  }, [])

  // Recursive function to convert JSON to tree data
  const convertToTreeData = useCallback(
    (obj, key = 'root', path = '') => {
      const currentPath = path ? `${path}.${key}` : key
      const dataInfo = getDataTypeInfo(obj)

      const node = {
        title: (
          <Space size='small'>
            <Tag color={dataInfo.color} size='small' style={{ margin: 0 }}>
              {dataInfo.icon}
            </Tag>
            <Text strong>{key}</Text>
            {showKeyCopy && (
              <CopyButton text={key} tooltip={`Copy key: ${key}`} />
            )}
            <Text type='secondary'>({dataInfo.type})</Text>
            {dataInfo.type !== 'object' && dataInfo.type !== 'array' && (
              <>
                <Text code>{formatValue(obj)}</Text>
                {showValueCopy && (
                  <CopyButton
                    text={getCopyValue(obj)}
                    tooltip={`Copy ${dataInfo.type} value`}
                  />
                )}
              </>
            )}
            {(dataInfo.type === 'object' || dataInfo.type === 'array') &&
              showValueCopy && (
                <CopyButton
                  text={getCopyValue(obj)}
                  tooltip={`Copy ${dataInfo.type} as JSON`}
                />
              )}
          </Space>
        ),
        key: currentPath,
        value: obj,
        path: currentPath
      }

      // Add children for objects and arrays
      if (typeof obj === 'object' && obj !== null) {
        if (Array.isArray(obj)) {
          node.children = obj.map((item, index) =>
            convertToTreeData(item, `[${index}]`, currentPath)
          )
        } else {
          node.children = Object.entries(obj).map(([childKey, childValue]) =>
            convertToTreeData(childValue, childKey, currentPath)
          )
        }
      }

      return node
    },
    [showValueCopy, getCopyValue, formatValue, showKeyCopy]
  )

  // Convert data to tree structure
  const treeData = useMemo(() => {
    if (!data) return []

    if (typeof data === 'object' && data !== null) {
      if (Array.isArray(data)) {
        return [convertToTreeData(data, 'root')]
      } else {
        return [convertToTreeData(data, 'root')]
      }
    } else {
      // Handle primitive values
      const dataInfo = getDataTypeInfo(data)
      return [
        {
          title: (
            <Space size='small'>
              <Tag color={dataInfo.color} size='small' style={{ margin: 0 }}>
                {dataInfo.icon}
              </Tag>
              <Text strong>Value</Text>
              <Text type='secondary'>({dataInfo.type})</Text>
              <Text code>{formatValue(data)}</Text>
              {showValueCopy && (
                <CopyButton
                  text={getCopyValue(data)}
                  tooltip={`Copy ${dataInfo.type} value`}
                />
              )}
            </Space>
          ),
          key: 'root',
          value: data,
          path: 'root'
        }
      ]
    }
  }, [data, showValueCopy, convertToTreeData, getCopyValue, formatValue])

  // Handle node selection
  const handleSelect = (selectedKeys, { selected, selectedNodes }) => {
    setSelectedKeys(selectedKeys)
    if (onNodeSelect && selected && selectedNodes.length > 0) {
      const node = selectedNodes[0]
      onNodeSelect({
        key: node.key,
        value: node.value,
        path: node.path
      })
    }
  }

  // Handle expand/collapse
  const handleExpand = (keys) => {
    setExpandedKeys(keys)
  }

  // Auto-expand all if requested
  const getExpandedKeys = () => {
    if (defaultExpandAll) {
      return treeData.length > 0 ? getAllKeys(treeData[0]) : []
    }
    return expandedKeys
  }

  // Helper function to get all keys for auto-expand
  const getAllKeys = (node) => {
    let keys = [node.key]
    if (node.children) {
      node.children.forEach((child) => {
        keys = keys.concat(getAllKeys(child))
      })
    }
    return keys
  }

  return (
    <Tree
      rootStyle={{ background: 'transparent', ...style }}
      treeData={treeData}
      expandedKeys={getExpandedKeys()}
      selectedKeys={selectedKeys}
      onExpand={handleExpand}
      onSelect={handleSelect}
      showLine={showLine}
      showIcon={false}
      blockNode
    />
  )
}

DataTree.propTypes = {
  data: PropTypes.any.isRequired,
  showLine: PropTypes.bool,
  showValueCopy: PropTypes.bool,
  showKeyCopy: PropTypes.bool,
  defaultExpandAll: PropTypes.bool,
  onNodeSelect: PropTypes.func,
  style: PropTypes.object
}

export default DataTree
