import { useEffect, useRef, useState } from 'react'
import 'ol/ol.css'
import OlMap from 'ol/Map'
import { v4 as uuidv4 } from 'uuid'
import TileLayer from 'ol/layer/Tile'
import { OSM } from 'ol/source'
import View from 'ol/View'
import { transform } from 'ol/proj'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import Feature from 'ol/Feature'
import { LineString } from 'ol/geom'
import { Stroke, Style, Text } from 'ol/style'
import { Tab, TabList } from '@fluentui/react-components'

const center = [14443331.466543002, 8878970.176309839]

const style = new Style({
    stroke: new Stroke({ color: 'blue', width: 2 }),
    text: new Text({
        font: 'bold 14px',
        placement: 'line',
        offsetY: -14
    }),
})

const MapLineTest = () => {
    const lines = [
        { name: 'A', points: [[100, 100], [200, 200]] },
        { name: 'B', points: [[200, 200], [300, 200]] },
        { name: 'X', points: [[200, 200], [300, 300]] },
        { name: 'L', points: [[300, 300], [350, 300]] },
        { name: 'N', points: [[300, 300], [250, 300]] },
        { name: 'I', points: [[300, 200], [300, 100]] },
        { name: 'J', points: [[300, 100], [250, 50]] },
        { name: 'C', points: [[300, 200], [400, 150]] },
        { name: 'D', points: [[400, 150], [400, 100]] },
    ]

    const map = useRef<OlMap | null>(null)
    const vectorLayer = useRef(new VectorLayer({
        source: new VectorSource(),
        style: feature => {
            style.getText()?.setText(feature.get('label'))
            return style
        }
    }))

    const mapElement = useRef<HTMLDivElement | null>(null)

    useEffect(() => {
        map.current = new OlMap({
            controls: [],
            layers: [
                new TileLayer({ source: new OSM(), properties: { id: uuidv4(), name: 'OpenStreetMap' } }),
                vectorLayer.current
            ]
        })
        map.current.setTarget(mapElement.current as HTMLDivElement)
        map.current.setView(new View({
            center: transform([129.7466541, 62.083504], 'EPSG:4326', 'EPSG:3857'),
            zoom: 16,
            maxZoom: 21,
        }))
    }, [])

    useEffect(() => {
        if (map.current) {
            const graph = new Map<string, { node: string, distance: number }[]>()

            // build graph adjacency list
            lines.forEach(({ points }) => {
                const [start, end] = points.map(pt => pt.join(','))
                const distance = Math.hypot(points[1][0] - points[0][0], points[1][1] - points[0][1])

                if (!graph.has(start)) graph.set(start, [])
                if (!graph.has(end)) graph.set(end, [])

                graph.get(start)?.push({ node: end, distance })
                graph.get(end)?.push({ node: start, distance })
            })

            // perform DFS to calculate distances from "A"
            const startNode = lines[0].points[0].join(',')
            const distances = new Map<string, number>()
            const dfs = (node: string, currentDist: number) => {
                if (distances.has(node) && distances.get(node)! <= currentDist) return
                distances.set(node, currentDist)
                for (const { node: neighbor, distance } of graph.get(node) || []) {
                    dfs(neighbor, currentDist + distance)
                }
            }
            dfs(startNode, 0)

            // render features
            lines.forEach(({ name, points }) => {
                const lineCoords = points.map(point => [point[0] + center[0], point[1] + center[1]])
                const feature = new Feature(new LineString(lineCoords))

                const lastNode = points[1].join(',')
                const label = `${name} ${feature.getGeometry()?.getLength().toFixed(2)} (${distances.get(lastNode)?.toFixed(1) ?? '∞'})`

                feature.set('label', label)
                vectorLayer.current.getSource()?.addFeature(feature)
            })
        }
    }, [])

    const [selectedTab, setSelectedTab] = useState<string | unknown>('map')

    return (
        <div style={{ position: 'relative', width: '100%' }}>

            <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
                <TabList selectedValue='map' onTabSelect={(_, data) => setSelectedTab(data.value)}>
                    <Tab value='map'>
                        Map
                    </Tab>
                </TabList>
                {selectedTab === 'map' && <div style={{ width: '100%', height: '100%' }} ref={mapElement}></div>}

            </div>
        </div>
    )
}

export default MapLineTest
