import {
    useCallback,
    useEffect,
    useMemo,
    useState,
    useRef,
} from 'react'
import {
    useLocation,
    useNavigate,
    useSearchParams,
} from 'react-router-dom'
import { useMutation, useQuery } from '@apollo/client/react'
import { m } from 'framer-motion'

import { DELETE_ORGANISATION_MUTATION, GET_ORGANISATIONS_QUERY } from '../../../../entities/employee/api/employee.graphql'
import type {
    GetOrganisationsData,
    GetOrganisationsVariables,
    Organisation,
    DeleteOrganisationData,
    DeleteOrganisationVariables,
} from '../../../../entities/employee/model/types'
import {
    EmployeesToolbar,
    organisationsSortOptions,
} from '../EmployeesToolbar/EmployeesToolbar'
import { EmployeesPagination } from '../EmployeesPagination/EmployeesPagination'
import { OrganisationsTable } from '../OrganisationsTable/OrganisationsTable'
import { ConfirmDangerDialog } from '../../../../widgets/ConfirmDangerDialog/ConfirmDangerDialog'
import { getPaginationItems } from '../../lib/getPaginationItems'
import {
    TableSkeleton,
    type TableSkeletonColumn,
} from '../../../../shared/ui/TableSkeleton/TableSkeleton'
import { RevealContent } from '../../../../shared/ui/RevealContent/RevealContent'
import { pageSwapVariants, uiFadeTransition } from '../../../../shared/lib/motion'
import { EmptyState } from '../../../../shared/ui/EmptyState/EmptyState'
import {
    useDeferredModalPayload,
} from '../../../../shared/lib/lazyMount'
import { AddOrganisationModal } from '../AddOrganisationModal/AddOrganisationModal'

import SimpleBar from "simplebar-react";
import "simplebar-react/dist/simplebar.min.css";

const ORGANISATIONS_SCROLL_KEY = 'employees.organisations.scrollTop'

const organisationsTableSkeletonColumns: TableSkeletonColumn[] = [
    { width: '50px', headerWidth: '34px' },
    { variant: 'person', width: '72%', headerWidth: '180px' },
    { variant: 'actions', headerWidth: '132px' },
]

export function OrganisationsSection() {
    const navigate = useNavigate()

    const location = useLocation()
    const [searchParams, setSearchParams] = useSearchParams()
    const tableCardRef = useRef<HTMLDivElement | null>(null)

    const organisationsCurrentPage = Number(searchParams.get('oPage') ?? 0)
    const organisationSearch = searchParams.get('oQuery') ?? ''

    const organisationSort = useMemo(() => {
        return organisationsSortOptions.find(
            (option) => option.value === searchParams.get('oSort'),
        ) ?? organisationsSortOptions[0]
    }, [searchParams])

    const [debouncedOrganisationSearch, setDebouncedOrganisationSearch] =
        useState('')

    const [isAddOrganisationOpen, setIsAddOrganisationOpen] = useState(false)
    const [editingOrganisation, setEditingOrganisation] =
        useState<Organisation | null>(null)
    const [deletingOrganisation, setDeletingOrganisation] =
        useState<Organisation | null>(null)
    const renderEditingOrganisation =
        useDeferredModalPayload(editingOrganisation)
    const renderDeletingOrganisation =
        useDeferredModalPayload(deletingOrganisation)

    useEffect(() => {
        const timeoutId = window.setTimeout(() => {
            setDebouncedOrganisationSearch(organisationSearch.trim())
        }, 350)

        return () => {
            window.clearTimeout(timeoutId)
        }
    }, [organisationSearch])

    const organisationsQueryVariables = useMemo<GetOrganisationsVariables>(
        () => ({
            page: organisationsCurrentPage,
            query: debouncedOrganisationSearch || undefined,
            sortDirection: organisationSort.sortDirection,
            sortField: organisationSort.sortField,
        }),
        [
            debouncedOrganisationSearch,
            organisationSort.sortDirection,
            organisationSort.sortField,
            organisationsCurrentPage,
        ],
    )

    const {
        data: organisationsData,
        previousData: previousOrganisationsData,
        loading: organisationsLoading,
        error: organisationsError,
        refetch: refetchOrganisations,
    } = useQuery<GetOrganisationsData, GetOrganisationsVariables>(
        GET_ORGANISATIONS_QUERY,
        {
            variables: organisationsQueryVariables,
            fetchPolicy: 'cache-first',
            notifyOnNetworkStatusChange: true,
        },
    )

    const [deleteOrganisation, { loading: isDeletingOrganisation }] =
        useMutation<DeleteOrganisationData, DeleteOrganisationVariables>(
            DELETE_ORGANISATION_MUTATION,
        )

    const organisationsResponse =
        organisationsData?.getOrganisations ??
        previousOrganisationsData?.getOrganisations

    const organisations = organisationsResponse?.page ?? []
    const organisationsTotalPages = organisationsResponse?.totalPages ?? 0

    const isOrganisationsInitialLoading =
        organisationsLoading && !organisationsResponse

    const isOrganisationsUpdating =
        organisationsLoading && Boolean(organisationsResponse)
    const shouldShowOrganisationsError =
        Boolean(organisationsError) && organisations.length === 0
    const hasAppliedOrganisationFilters = Boolean(
        debouncedOrganisationSearch,
    )

    const hasPrevOrganisationsPage = organisationsCurrentPage > 0
    const hasNextOrganisationsPage =
        organisationsTotalPages > 0 &&
        organisationsCurrentPage < organisationsTotalPages - 1

    const organisationsPaginationItems = useMemo(
        () => getPaginationItems(
            organisationsCurrentPage,
            organisationsTotalPages,
        ),
        [organisationsCurrentPage, organisationsTotalPages],
    )

    useEffect(() => {
        if (isOrganisationsInitialLoading) return

        

        const element = tableCardRef.current

        if (!element) return

        const savedScrollTop = Number(
            sessionStorage.getItem(ORGANISATIONS_SCROLL_KEY) ?? 0,
        )

        const frameId = window.requestAnimationFrame(() => {
            element.scrollTop = savedScrollTop
        })

        return () => {
            window.cancelAnimationFrame(frameId)
        }
    }, [isOrganisationsInitialLoading, organisationsCurrentPage])

    const updateOrganisationsSearchParams = useCallback((
        updates: Record<string, string | null>,
    ) => {
        setSearchParams(
            (prev) => {
                const next = new URLSearchParams(prev)

                Object.entries(updates).forEach(([key, value]) => {
                    if (value === null || value === '') {
                        next.delete(key)
                        return
                    }

                    next.set(key, value)
                })

                return next
            },
            {
                replace: true,
            },
        )
    }, [setSearchParams])

    const resetOrganisationsScroll = useCallback(() => {
        sessionStorage.setItem(ORGANISATIONS_SCROLL_KEY, '0')
    }, [])

    const handleOrganisationsScroll = useCallback(() => {
        const element = tableCardRef.current

        if (!element) return

        sessionStorage.setItem(
            ORGANISATIONS_SCROLL_KEY,
            String(element.scrollTop),
        )
    }, [])

    const tableScrollProps = useMemo(
        () => ({
            ref: tableCardRef,
            onScroll: handleOrganisationsScroll,
        }),
        [handleOrganisationsScroll],
    )

    const setOrganisationsPage = useCallback((page: number) => {
        resetOrganisationsScroll()

        updateOrganisationsSearchParams({
            oPage: page > 0 ? String(page) : null,
        })
    }, [resetOrganisationsScroll, updateOrganisationsSearchParams])

    const handleNextOrganisationsPage = useCallback(() => {
        if (!hasNextOrganisationsPage || organisationsLoading) return

        setOrganisationsPage(organisationsCurrentPage + 1)
    }, [
        hasNextOrganisationsPage,
        organisationsCurrentPage,
        organisationsLoading,
        setOrganisationsPage,
    ])

    const handlePrevOrganisationsPage = useCallback(() => {
        if (!hasPrevOrganisationsPage || organisationsLoading) return

        setOrganisationsPage(Math.max(0, organisationsCurrentPage - 1))
    }, [
        hasPrevOrganisationsPage,
        organisationsCurrentPage,
        organisationsLoading,
        setOrganisationsPage,
    ])

    const handleJumpPrevOrganisationsPage = useCallback(() => {
        if (organisationsLoading) return

        setOrganisationsPage(Math.max(0, organisationsCurrentPage - 5))
    }, [organisationsCurrentPage, organisationsLoading, setOrganisationsPage])

    const handleJumpNextOrganisationsPage = useCallback(() => {
        if (organisationsLoading) return

        setOrganisationsPage(
            Math.min(organisationsTotalPages - 1, organisationsCurrentPage + 5),
        )
    }, [
        organisationsCurrentPage,
        organisationsLoading,
        organisationsTotalPages,
        setOrganisationsPage,
    ])

    const refetchFirstOrganisationsPage = useCallback(async () => {
        resetOrganisationsScroll()

        updateOrganisationsSearchParams({
            oPage: null,
        })

        await refetchOrganisations({
            ...organisationsQueryVariables,
            page: 0,
        })
    }, [
        organisationsQueryVariables,
        refetchOrganisations,
        resetOrganisationsScroll,
        updateOrganisationsSearchParams,
    ])

    const handleOpenOrganisation = useCallback((organisation: Organisation) => {
        navigate(`/employees/organisations/${organisation.id}`, {
            state: {
                fromEmployeesPath: `${location.pathname}${location.search}`,
            },
        })
    }, [location.pathname, location.search, navigate])

    const handleEditOrganisation = useCallback((organisation: Organisation) => {
        setEditingOrganisation(organisation)
    }, [])

    const handleDeleteOrganisation = useCallback((organisation: Organisation) => {
        setDeletingOrganisation(organisation)
    }, [])

    const handleConfirmDeleteOrganisation = useCallback(async () => {
        if (!deletingOrganisation) return

        try {
            await deleteOrganisation({
                variables: {
                    id: String(deletingOrganisation.id),
                },
            })

            const nextPage =
                organisations.length === 1 && organisationsCurrentPage > 0
                    ? organisationsCurrentPage - 1
                    : organisationsCurrentPage

            setDeletingOrganisation(null)

            if (nextPage !== organisationsCurrentPage) {
                updateOrganisationsSearchParams({
                    oPage: nextPage > 0 ? String(nextPage) : null,
                })
            }

            await refetchOrganisations({
                page: nextPage,
                query: debouncedOrganisationSearch || undefined,
                sortDirection: organisationSort.sortDirection,
                sortField: organisationSort.sortField,
            })
        } catch (error) {
            console.error('Не удалось удалить организацию', error)
        }
    }, [
        debouncedOrganisationSearch,
        deleteOrganisation,
        deletingOrganisation,
        organisationSort.sortDirection,
        organisationSort.sortField,
        organisations.length,
        organisationsCurrentPage,
        refetchOrganisations,
        updateOrganisationsSearchParams,
    ])

    const handleOrganisationSearchChange = useCallback((value: string) => {
        resetOrganisationsScroll()

        updateOrganisationsSearchParams({
            oQuery: value || null,
            oPage: null,
        })
    }, [resetOrganisationsScroll, updateOrganisationsSearchParams])

    const handleOrganisationSortChange = useCallback((
        option: typeof organisationsSortOptions[number],
    ) => {
        resetOrganisationsScroll()

        updateOrganisationsSearchParams({
            oSort:
                option.value === organisationsSortOptions[0].value
                    ? null
                    : option.value,
            oPage: null,
        })
    }, [resetOrganisationsScroll, updateOrganisationsSearchParams])

    const handleOpenAddOrganisation = useCallback(() => {
        setIsAddOrganisationOpen(true)
    }, [])

    const handleEditOrganisationOpenChange = useCallback((open: boolean) => {
        if (!open) {
            setEditingOrganisation(null)
        }
    }, [])

    const handleDeleteOrganisationOpenChange = useCallback((open: boolean) => {
        if (!open) {
            setDeletingOrganisation(null)
        }
    }, [])
    return (
        <>
            <EmployeesToolbar
                addButtonText="Добавить организацию"
                searchValue={organisationSearch}
                onSearchChange={handleOrganisationSearchChange}
                sortOptions={organisationsSortOptions}
                selectedSort={organisationSort}
                onSortChange={handleOrganisationSortChange}
                showSort
                onAdd={handleOpenAddOrganisation}
            />
            <m.div
                key="organisations-table"
                className="employees-page__table-motion"
                variants={pageSwapVariants}
                initial="initial"
                animate="animate"
                transition={uiFadeTransition}
            >
            <div className="employees-table-container">
                <div className="employees-table-shadow">
                <SimpleBar
                    scrollableNodeProps={tableScrollProps}
                    className={`employees-table-card ${isOrganisationsUpdating ? 'is-updating' : ''
                        }`}
                >
                    <RevealContent
                        loading={isOrganisationsInitialLoading}
                        fallback={
                            <TableSkeleton
                                className="employees-table organisations-table"
                                columns={organisationsTableSkeletonColumns}
                            />
                        }
                    >
                        {shouldShowOrganisationsError && (
                            <div className="employees-state employees-state--error">
                                Не удалось загрузить организации
                            </div>
                        )}

                        {!organisationsError && organisations.length === 0 && (
                            <EmptyState
                                className="employees-state"
                                variant={
                                    hasAppliedOrganisationFilters
                                        ? 'not-found'
                                        : 'no-items'
                                }
                                title={
                                    hasAppliedOrganisationFilters
                                        ? 'Не найдено результатов'
                                        : 'Организаций пока нет'
                                }
                                description={
                                    hasAppliedOrganisationFilters
                                        ? 'По заданным параметрам не найдено ни одной организации. Попробуйте изменить поиск.'
                                        : 'Добавьте организацию, чтобы привязать сотрудников и устройства.'
                                }
                            />
                        )}

                        {organisations.length > 0 && (
                            <OrganisationsTable
                                organisations={organisations}
                                onOpen={handleOpenOrganisation}
                                onEdit={handleEditOrganisation}
                                onDelete={handleDeleteOrganisation}
                            />
                        )}
                    </RevealContent>
                </SimpleBar>
                </div>

                {organisationsTotalPages > 1 && (
                    <EmployeesPagination
                        currentPage={organisationsCurrentPage}
                        loading={organisationsLoading}
                        items={organisationsPaginationItems}
                        hasPrevPage={hasPrevOrganisationsPage}
                        hasNextPage={hasNextOrganisationsPage}
                        onPrev={handlePrevOrganisationsPage}
                        onNext={handleNextOrganisationsPage}
                        onJumpPrev={handleJumpPrevOrganisationsPage}
                        onJumpNext={handleJumpNextOrganisationsPage}
                        onPageChange={setOrganisationsPage}
                    />
                )}
            </div>
            </m.div>

            <AddOrganisationModal
                open={isAddOrganisationOpen}
                mode="create"
                onOpenChange={setIsAddOrganisationOpen}
                onSuccess={refetchFirstOrganisationsPage}
            />

            <AddOrganisationModal
                open={Boolean(editingOrganisation)}
                mode="edit"
                organisation={
                    editingOrganisation ?? renderEditingOrganisation
                }
                onOpenChange={handleEditOrganisationOpenChange}
                onSuccess={refetchFirstOrganisationsPage}
            />

            <ConfirmDangerDialog
                open={Boolean(deletingOrganisation)}
                title="Удалить организацию?"
                description={
                    renderDeletingOrganisation
                        ? `Организация «${renderDeletingOrganisation.name}» будет удалена из системы. Это действие нельзя будет отменить.`
                        : ''
                }
                confirmText="Удалить"
                isLoading={isDeletingOrganisation}
                onOpenChange={handleDeleteOrganisationOpenChange}
                onConfirm={handleConfirmDeleteOrganisation}
            />
        </>
    )
}
