import { Button, Drawer, Skeleton, Tree, TreeDataNode, TreeProps, Typography } from 'antd'
import { useState, useEffect, useCallback, memo, Key } from 'react'
import { useNavigate, useLocation } from 'react-router-dom'

import { WellIcon, WellIconState } from '@components/icons'
import { invokeWebApiWrapperAsync } from '@components/factory'
import { DepositService, DepositDto, WellDto } from '@api'
import { isRawDate } from '@utils'

import { ReactComponent as DepositIcon } from '@images/DepositIcon.svg'
import { ReactComponent as ClusterIcon } from '@images/ClusterIcon.svg'

import '@styles/wellTreeSelect.css'

export const getWellState = (idState?: number): WellIconState => idState === 1 ? 'active' : 'unknown'
export const checkIsWellOnline = (lastTelemetryDate: unknown): boolean =>
    isRawDate(lastTelemetryDate) && (Date.now() - +new Date(lastTelemetryDate) < 600_000)

const getKeyByUrl = (url?: string): [Key | null, string | null] => {
    const result = url?.match(/^\/([^\/]+)\/([^\/?]+)/) // pattern "/:type/:id"
    if (!result) return [null, null]
    return [result[0], result[1]]
}

const getLabel = (wellsTree: TreeDataNode[], value?: string): string | undefined => {
    const [url, type] = getKeyByUrl(value)
    if (!url) return
    let deposit: TreeDataNode | undefined
    let cluster: TreeDataNode | undefined
    let well: TreeDataNode | undefined
    switch (type) {
        case 'deposit':
            deposit = wellsTree.find((deposit) => deposit.key === url)
            if (deposit)
                return `${deposit.title}`
            return 'Ошибка! Месторождение не найдено!'

        case 'cluster':
            deposit = wellsTree.find((deposit) => (
                cluster = deposit.children?.find((cluster: TreeDataNode) => cluster.key === url)
            ))
            if (deposit && cluster)
                return `${deposit.title} / ${cluster.title}`
            return 'Ошибка! Куст не найден!'

        case 'well':
            deposit = wellsTree.find((deposit) => (
                cluster = deposit.children?.find((cluster: TreeDataNode) => (
                    well = cluster.children?.find((well: TreeDataNode) => well.key === url)
                ))
            ))
            if (deposit && cluster && well)
                return `${deposit.title} / ${cluster.title} / ${well.title}`
            return 'Ошибка! Скважина не найдена!'

        default: break
    }
}

const getWellSortScore = (well: WellDto) => {
    let out = [1, 2, 0][well.idState ?? 2]
    const timeout = Date.now() - +new Date(well.lastTelemetryDate || 0)
    if (timeout < 600_000) out += 600_000 - timeout
    return out
}

const sortWellsByActive = (a: WellDto, b: WellDto): number => {
    const score = getWellSortScore(b) - getWellSortScore(a)
    if (score !== 0) return score
    return (a.caption || '')?.localeCompare(b.caption || '')
}

export type WellTreeSelectorProps = TreeProps<TreeDataNode> & {
    show?: boolean
    expand?: boolean | Key[]
    current?: Key
    onClose?: () => void
    onChange?: (value: string | undefined) => void
    open?: boolean
}

const getExpandKeys = (treeData: TreeDataNode[], depositKeys?: Key[] | boolean): Key[] => {
    const out: Key[] = []
    treeData.forEach((deposit) => {
        if (Array.isArray(depositKeys) && !depositKeys.includes(deposit.key)) return
        if (deposit.key) out.push(deposit.key)
        deposit.children?.forEach((cluster) => {
            if (cluster.key) out.push(cluster.key)
        })
    })
    return out
}

export const WellTreeSelector = memo<WellTreeSelectorProps>(({ expand, current, onChange, onClose, open, ...other }) => {
    const [wellsTree, setWellsTree] = useState<TreeDataNode[]>([])
    const [showLoader, setShowLoader] = useState<boolean>(false)
    const [expanded, setExpanded] = useState<Key[]>([])
    const [selected, setSelected] = useState<Key[]>([])

    const navigate = useNavigate()
    const location = useLocation()

    useEffect(() => {
        if (current) setSelected([current])
    }, [current])

    useEffect(() => {
        setExpanded((prev) => expand ? getExpandKeys(wellsTree, expand) : prev)
    }, [wellsTree, expand])

    useEffect(() => {
        invokeWebApiWrapperAsync(
            async () => {
                const deposits: Array<DepositDto> = await DepositService.getDeposits()
                const wellsTree: TreeDataNode[] = deposits.map(deposit =>({
                    title: deposit.caption,
                    key: `/deposit/${deposit.id}`,
                    value: `/deposit/${deposit.id}`,
                    icon: <DepositIcon width={24} height={24}/>,
                    children: deposit.clusters?.map(cluster => {
                        const wells = cluster.wells ? cluster.wells.slice() : []
                        wells.sort(sortWellsByActive)

                        return {
                            title: cluster.caption,
                            key: `/cluster/${cluster.id}`,
                            value: `/cluster/${cluster.id}`,
                            icon: <ClusterIcon width={24} height={24}/>,
                            children: wells.map(well => ({
                                title: well.caption,
                                key: `/well/${well.id}`,
                                value: `/well/${well.id}`,
                                icon: <WellIcon
                                    width={24}
                                    height={24}
                                    state={getWellState(well.idState)}
                                    online={checkIsWellOnline(well.lastTelemetryDate)}
                                />
                            })),
                        }
                    }),
                }))
                setWellsTree(wellsTree)
            },
            setShowLoader,
            `Не удалось загрузить список скважин`,
            { actionName: 'Получить список скважин' }
        )
    }, [])

    const onValueChange = useCallback((value?: string): void => {
        const key = getKeyByUrl(value)[0]
        setSelected(key ? [key] : [])
        onChange?.(getLabel(wellsTree, value))
    }, [wellsTree])

    const onSelect = useCallback((value: Key[]): void => {
        const newRoot = /\/(\w+)\/\d+/.exec(String(value))
        const oldRoot = /\/(\w+)(?:\/\d+)?/.exec(location.pathname)
        if (!newRoot || !oldRoot) return

        let newPath = newRoot[0]
        if (oldRoot[1] === newRoot[1]) {
            /// Если типы страницы одинаковые (deposit, cluster, well), добавляем остаток старого пути
            const url = location.pathname.substring(oldRoot[0].length)
            newPath = newPath + url
        }

        navigate(newPath, { state: { from: location.pathname }})
    }, [navigate, location])

    useEffect(() => onValueChange(location.pathname), [onValueChange, location])

    return (
        <Drawer open={open} mask={false} onClose={onClose} title={'Список скважин'}>
            <Skeleton active loading={showLoader}>
                <Tree
                    {...other}
                    showIcon
                    selectedKeys={selected}
                    treeData={wellsTree}
                    onSelect={onSelect}
                    onExpand={setExpanded}
                    expandedKeys={expanded}
                />
            </Skeleton>
        </Drawer>
    )
})

export default WellTreeSelector
