/*
 * @Author: ZhaoYing 
 * @Date: 2026-02-03 18:32:00 
 * @Last Modified by: ZhaoYing
 * @Last Modified time: 2026-03-13 14:51:17
 */
/**
 * Relationship Network Component
 * Displays memory relationship graph with node details
 * Interactive force-directed graph visualization
 */

import React, { type FC, useEffect, useState, useRef, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams, useNavigate } from 'react-router-dom'
import { Col, Row, Space, Button, Tabs, Flex, Divider } from 'antd'
import dayjs from 'dayjs'
import ReactEcharts from 'echarts-for-react'

import RbCard from '@/components/RbCard/Card'
import detailEmpty from '@/assets/images/userMemory/detail_empty.png'
import type { Node, Edge, GraphData, StatementNodeProperties, ExtractedEntityNodeProperties } from '../types'
import type { RawCommunityNode } from '@/components/D3Graph/types'
import {
  getMemorySearchEdges,
} from '@/api/memory'
import Empty from '@/components/Empty'
import Tag from '@/components/Tag'
import CommunityNetwork from './CommunityNetwork'

/** Node color palette */
const colors = ['#155EEF', '#369F21', '#4DA8FF', '#FF5D34', '#9C6FFF', '#FF8A4C', '#8BAEF7', '#FFB048']
const RelationshipNetwork:FC = () => {
  const { t } = useTranslation()
  const { id } = useParams()
  const chartRef = useRef<ReactEcharts>(null)
  const resizeScheduledRef = useRef(false)
  const [nodes, setNodes] = useState<Node[]>([])
  const [links, setLinks] = useState<Edge[]>([])
  const [categories, setCategories] = useState<{ name: string }[]>([])
  const [selectedNode, setSelectedNode] = useState<Node | RawCommunityNode | null>(null)
  // const [fullScreen, setFullScreen] = useState<boolean>(false)
  const navigate = useNavigate()
  const [activeTab, setActiveTab] = useState('relationshipNetwork')

  console.log('categories', categories)
  const edgeAbortRef = useRef<AbortController | null>(null)

  /** Fetch relationship network data */
  const getEdgeData = useCallback(() => {
    if (!id) return
    edgeAbortRef.current?.abort()
    edgeAbortRef.current = new AbortController()
    setSelectedNode(null)
    getMemorySearchEdges(id, { signal: edgeAbortRef.current.signal }).then((res) => {
      const { nodes, edges, statistics } = res as GraphData
      const curNodes: Node[] = []
      const curEdges: Edge[] = []
      const curNodeTypes = Object.keys(statistics.node_types).filter(vo => vo !== 'Dialogue')
      
      // Calculate connection count for each node
      const connectionCount: Record<string, number> = {}
      edges.forEach(edge => {
        connectionCount[edge.source] = (connectionCount[edge.source] || 0) + 1
        connectionCount[edge.target] = (connectionCount[edge.target] || 0) + 1
      })
      
      // Process node data
      nodes.filter(vo => vo.label !== 'Dialogue').forEach(node => {
        const connections = connectionCount[node.id] || 0
        const categoryIndex = curNodeTypes.indexOf(node.label)
        
        // Get display name based on node type
        let displayName = ''
        switch (node.label) {
          // case 'Statement':
          //   displayName = 'statement' in node.properties ? node.properties.statement?.slice(0, 5) || '' : ''
          //   break
          case 'ExtractedEntity':
            displayName = 'name' in node.properties ? node.properties.name || '' : ''
            break
          // default:
          //   displayName = 'content' in node.properties ? node.properties.content?.slice(0, 5) || '' : ''
          //   break
        }
        let symbolSize = 0
        if (connections <= 1) {
          symbolSize = 5
        } else if (connections <= 10) {
          symbolSize = 10
        } else if (connections <= 15) {
          symbolSize = 15
        } else if (connections <= 20) {
          symbolSize = 25
        } else {
          symbolSize = 35
        }
        
        curNodes.push({
          ...node,
          name: displayName,
          category: categoryIndex >= 0 ? categoryIndex : 0,
          symbolSize: symbolSize, // Adjust node size based on connection count
        })
      })
      
      // Create mapping from node ID to label
      const nodeIdToLabel: Record<string, string> = {}
      nodes.forEach(node => {
        nodeIdToLabel[node.id] = node.label
      })
      // Process edge data
      edges.forEach(edge => {
        curEdges.push({
          ...edge,
          source: edge.source,
          target: edge.target,
          value: edge.weight || 1
        })
      })
      
      // Set categories
      const curCategories = curNodeTypes.map(type => ({ name: type }))
      
      setNodes(curNodes)
      setLinks(curEdges)
      setCategories(curCategories)
    })
  }, [id])
  useEffect(() => {
    if (!id) return
    getEdgeData()
    return () => { edgeAbortRef.current?.abort() }
  }, [id])
  
  useEffect(() => {
    const handleResize = () => {
      if (chartRef.current && !resizeScheduledRef.current) {
        resizeScheduledRef.current = true
        requestAnimationFrame(() => {
          chartRef.current?.getEchartsInstance().resize();
          resizeScheduledRef.current = false
        });
      }
    }

    const resizeObserver = new ResizeObserver(handleResize)
    const chartElement = chartRef.current?.getEchartsInstance().getDom().parentElement
    if (chartElement) {
      resizeObserver.observe(chartElement)
    }
    
    return () => {
      resizeObserver.disconnect()
    }
  }, [nodes])

  /** Navigate to full graph view */
  const handleViewAll = () => {
    if (!selectedNode) return
    const params = new URLSearchParams({
      nodeId: selectedNode.id,
      nodeLabel: selectedNode.label,
      nodeName: (selectedNode as Node).name || ''
    })
    navigate(`/user-memory/detail/${id}/GRAPH?${params.toString()}`)
  }
  const handleChangeTab = (tab: string) => {
    if (tab === 'communityNetwork') {
      edgeAbortRef.current?.abort()
    } else {
      getEdgeData()
    }
    setActiveTab(tab)
    setSelectedNode(null)
  }

  return (
    <Row gutter={16}>
      {/* Relationship Network */}
      <Col span={16}>
        <RbCard bodyClassName="rb:pt-0!">
          <Tabs
            items={['relationshipNetwork', 'communityNetwork'].map(key => ({ key, label: t(`userMemory.${key}`) }))}
            activeKey={activeTab}
            onChange={handleChangeTab}
          />
          <div className="rb:h-129.5 rb:bg-[#F6F8FC] rb:border rb:border-[#DFE4ED] rb:rounded-sm">
            {activeTab === 'communityNetwork'
              ? <CommunityNetwork onSelectCommunity={community => setSelectedNode(community)} />
              : nodes.length === 0
              ? <Empty className="rb:h-full" />
              : <ReactEcharts
                option={{
                  colors: colors,
                  tooltip: {
                    show: false
                  },
                  legend: {
                    show: true,
                    bottom: 12,
                  },
                  series: [
                    {
                      type: 'graph',
                      layout: 'force',
                      data: nodes || [],
                      links: links || [],
                      categories: categories.map(vo => ({
                        name: t(`userMemory.${vo.name}`)
                      })) || [],
                      roam: true,
                      label: {
                        show: true,
                        position: 'right',
                        formatter: '{b}',
                      },
                      lineStyle: {
                        color: '#5B6167',
                        curveness: 0.3
                      },
                      force: {
                        repulsion: 100,
                        // Enable category aggregation
                        edgeLength: 80,
                        gravity: 0.3,
                        // Nodes of the same category attract each other
                        layoutAnimation: true,
                        // Prevent layout recalculation on click
                        preventOverlap: true,
                        // Keep layout stable after node click
                        edgeSymbol: ['none', 'arrow'],
                        edgeSymbolSize: [4, 10],
                        // Disable force-directed after initial layout
                        initLayout: 'force'
                      },
                      selectedMode: 'single',
                      draggable: true,
                      // Prevent layout recalculation on data update
                      animationDurationUpdate: 0,
                      select: {
                        itemStyle: {
                          borderWidth: 2,
                          borderColor: '#ffffff',
                          shadowBlur: 10,
                        }
                      }
                    }
                  ]
                }}
                style={{ height: '518px', width: '100%' }}
                notMerge={false}
                lazyUpdate={true}
                onEvents={{
                  // Node click event handler
                  click: (params: { dataType: string; data: Node; name: string }) => {
                    if (params.dataType === 'node') {
                      // Handle node click event
                      console.log('Node clicked:', params.data);
                      // Use functional update to avoid state dependency issues
                      setSelectedNode(params.data)
                    }
                  }
                }}
              />
            }
          </div>
        </RbCard>
      </Col>
      {/* Memory Details */}
      <Col span={8}>
        <RbCard
          title={t('userMemory.memoryDetails')}
          headerType="borderless"
          headerClassName="rb:min-h-[46px]!"
          bodyClassName="rb:p-0!"
          extra={selectedNode && !(selectedNode as RawCommunityNode).properties.community_id && (
            <Button type="text" onClick={handleViewAll}>
              <div className="rb:w-5 rb:h-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/userMemory/view.svg')] rb:hover:bg-[url('@/assets/images/userMemory/view_hover.svg')]" />
              {t('userMemory.completeMemory')}
            </Button>
          )}
        >
          <div className="rb:h-133.5 rb:overflow-y-auto">
            {!selectedNode
              ? <Empty url={detailEmpty} subTitle={activeTab === 'relationshipNetwork' ? t('userMemory.memoryDetailEmptyDesc') : t('userMemory.communityDetailEmptyDesc')} className="rb:h-full rb:mx-10 rb:text-center" size={[197.81, 150]} />
              : (selectedNode as RawCommunityNode).properties.community_id
                ? <div className="rb:p-3 rb:pt-0">
                  <div className="rb:font-medium rb:text-[#212332] rb:text-[16px] rb:leading-5.5 rb:pl-1">
                    {(selectedNode as RawCommunityNode).properties.name}
                  </div>
                  <div className="rb:mt-3 rb:font-medium rb:leading-5 rb:pl-1">{t('userMemory.summary')}</div>
                  <div className="rb:bg-[#F6F6F6] rb:rounded-xl rb:px-3 rb:py-2.5 rb:mt-2">
                    {(selectedNode as RawCommunityNode).properties.summary}
                  </div>
                  <Flex align="center" justify="space-between" className="rb:mt-5!">
                    <span className="rb:text-[#5B6167] rb:font-regular rb:pl-1">{t('userMemory.member_count')}</span>
                    <span className="rb:font-medium">{(selectedNode as RawCommunityNode).properties.member_count}{t('userMemory.member_count_desc')}</span>
                  </Flex>

                  <Divider className='rb:my-2.5!' />
                  <div className="rb:font-medium rb:leading-5 rb:pl-1">{t('userMemory.core_entities')}</div>
                  <ul className="rb:list-disc rb:pl-4 rb:text-[#5B6167] rb:mt-2">
                    {(selectedNode as RawCommunityNode).properties.core_entities.map((entity, index) => <li key={index}>{entity}</li>)}
                  </ul>
                </div>
                : <>
                  {(selectedNode as Node).name && (
                    <div className="rb:bg-[#F6F8FC] rb:border-t rb:border-b rb:border-[#DFE4ED] rb:font-medium rb:py-2 rb:px-4 rb:h-10">
                      {(selectedNode as Node).name}
                    </div>
                  )}
                  <div className="rb:p-4">
                    <div className="rb:font-medium rb:leading-5">{t('userMemory.memoryContent')}</div>
                    <div className="rb:text-[#5B6167] rb:font-regular rb:leading-5 rb:mt-1 rb:pb-4 rb:border-b rb:border-[#DFE4ED]">
                      {['Chunk', 'Dialogue', 'MemorySummary'].includes(selectedNode.label) && 'content' in selectedNode.properties
                        ? selectedNode.properties.content
                        : selectedNode.label === 'ExtractedEntity' && 'description' in selectedNode.properties
                          ? selectedNode.properties.description
                          : selectedNode.label === 'Statement' && 'statement' in selectedNode.properties
                            ? selectedNode.properties.statement
                            : ''}
                    </div>

                    <div className="rb:font-medium rb:mb-2 rb:mt-4">
                      <div className="rb:font-medium rb:leading-5">{t('userMemory.created_at')}</div>
                      <div className="rb:text-[#5B6167] rb:font-regular rb:leading-5 rb:mt-1 rb:pb-4 rb:border-b rb:border-[#DFE4ED]">
                        {dayjs((selectedNode as Node).properties.created_at).format('YYYY-MM-DD HH:mm:ss')}
                      </div>

                      {(selectedNode as Node).properties.associative_memory > 0 && (
                        <div className="rb:mt-4">
                          <div className="rb:font-medium rb:leading-5">{t('userMemory.associative_memory')}</div>
                          <div className="rb:text-[#5B6167] rb:font-regular rb:leading-5 rb:mt-1 rb:pb-4 rb:border-b rb:border-[#DFE4ED]">
                            <span className="rb:text-[#155EEF] rb:font-medium">{(selectedNode as Node).properties.associative_memory}</span>
                            {' '}{t('userMemory.unix')}{t('userMemory.associative_memory')}
                          </div>
                        </div>
                      )}

                      {selectedNode.label === 'Statement' && (
                        (['emotion_keywords', 'emotion_type', 'emotion_subject', 'importance_score'] as const).map(key => {
                          const p = selectedNode.properties as StatementNodeProperties
                          if ((key === 'emotion_keywords' && p[key]?.length > 0) || typeof p[key] === 'string') {
                            return (
                              <div className="rb:mt-4" key={key}>
                                {t(`userMemory.Statement_${key}`)}
                                <div className="rb:text-[#5B6167] rb:font-regular rb:leading-5 rb:mt-1 rb:pb-4 rb:border-b rb:border-[#DFE4ED]">
                                  {key === 'emotion_keywords'
                                    ? <Space>{p.emotion_keywords.map((v, i) => <Tag key={i}>{v}</Tag>)}</Space>
                                    : p[key]}
                                </div>
                              </div>
                            )
                          }
                          return null
                        })
                      )}

                      {selectedNode.label === 'ExtractedEntity' && (
                        (['name', 'entity_type', 'aliases', 'connect_strngth', 'importance_score'] as const).map(key => {
                          const p = selectedNode.properties as ExtractedEntityNodeProperties
                          if (p[key]) {
                            return (
                              <div className="rb:mt-4" key={key}>
                                {t(`userMemory.ExtractedEntity_${key}`)}
                                <div className="rb:text-[#5B6167] rb:font-regular rb:leading-5 rb:mt-1 rb:pb-4 rb:border-b rb:border-[#DFE4ED]">
                                  {Array.isArray(p[key]) && p[key].length > 0
                                    ? p[key].map((v, i) => <div key={i}>- {v}</div>)
                                    : p[key]}
                                </div>
                              </div>
                            )
                          }
                          return null
                        })
                      )}
                    </div>
                  </div>
                </>
            }
          </div>
        </RbCard>
      </Col>
    </Row>
  )
}
/** Use React.memo to avoid unnecessary renders */
export default React.memo(RelationshipNetwork)