import type { FC } from 'react';
import React from 'react';
import { Nav, SkeletonLoader } from '@theorchard/suite-components';
import { formatMessage } from '@theorchard/suite-i18n';
import { createHref } from '@theorchard/suite-utils';
import cx from 'classnames';
import { NavLink, useLocation, useParams } from 'react-router-dom';

export interface PageNavItem {
    route?: string;
    key: string;
    label: string | React.ReactNode;
    keepParams?: string[];
    dataAttributes?: object;
}

export interface PageNavProps {
    items: PageNavItem[];
    route?: string;
    params?: object;
    concatParameterValueByComma?: boolean;
    className?: string;
    right?: JSX.Element;
    tabParamName?: string;
    onItemMouseOver?: (item: PageNavItem) => void;
    onItemClick?: (item: PageNavItem) => void;
    loading?: boolean;
}

const CLASSNAME = 'PageNav';
export const TAB_PARAM_NAME = 'tab';

const createItemUrl = ({
    index,
    item,
    params,
    concatParameterValueByComma,
    route,
    tabParamName,
    location,
}: {
    index: number;
    item: PageNavItem;
    params: object;
    concatParameterValueByComma?: boolean;
    route?: string;
    tabParamName: string;
    location: ReturnType<typeof useLocation>;
}) => {
    let { search, pathname } = location;

    if (route) {
        const path = createHref(
            route,
            { ...params, [tabParamName]: item.key },
            concatParameterValueByComma
        );
        [pathname, search] = path.split('?');
    }

    const query = new URLSearchParams(search);

    if (!route) {
        if (index > 0) query.set(tabParamName, item.key);
        else query.delete(tabParamName);
    }

    if (item.keepParams) {
        const fromQuery = new URLSearchParams(location.search);

        item.keepParams.forEach((param) => {
            if (!query.has(param))
                fromQuery.getAll(param).forEach((value) => {
                    query.append(param, value);
                });
        });
    }

    return `${pathname}?${query.toString()}`;
};

const isActiveTab = ({
    tab,
    search,
    tabParamName,
    index,
}: {
    tab: string;
    search: string;
    tabParamName: string;
    index: number;
}) => {
    const query = new URLSearchParams(search);
    const tabValue = query.get(tabParamName);
    if (!tabValue && index === 0) return true;
    return tabValue === tab;
};

const normalizeDataAttributes = (dataAttributes?: object) =>
    dataAttributes
        ? Object.entries(dataAttributes).reduce((result, [key, value]) => {
              const dataKey = key.startsWith('data-') ? key : `data-${key}`;
              return { ...result, [dataKey]: value };
          }, {})
        : null;

const PageNav: FC<PageNavProps> = ({
    items,
    route,
    className,
    right,
    params = {},
    concatParameterValueByComma,
    tabParamName = TAB_PARAM_NAME,
    onItemMouseOver,
    onItemClick,
    loading,
}) => {
    const location = useLocation();
    const { [tabParamName]: activeTab } = useParams<Record<string, string>>();
    const defaultTab = items.find(({ key }) => !key);

    const isActiveItem = (item: PageNavItem, index: number) => {
        if (activeTab) return activeTab === item.key;
        if (defaultTab) return defaultTab === item;

        return isActiveTab({
            index,
            tab: item.key,
            search: location.search,
            tabParamName,
        });
    };

    if (loading)
        return (
            <div className={cx(`${CLASSNAME}-loading`)}>
                <SkeletonLoader numberOfItems={2} width={100} />
            </div>
        );

    return (
        <div className={cx(CLASSNAME, 'd-print-none', className)}>
            <Nav variant="tabs">
                {items.map((item, index) => (
                    <Nav.Item key={item.key} data-testid={`NavItem-${item.key}`}>
                        <NavLink
                            exact
                            className="nav-link"
                            onMouseOver={
                                onItemMouseOver &&
                                (() => {
                                    onItemMouseOver(item);
                                })
                            }
                            onClick={
                                onItemClick &&
                                (() => {
                                    onItemClick(item);
                                })
                            }
                            to={createItemUrl({
                                index,
                                item,
                                params,
                                concatParameterValueByComma,
                                route: item.route || route,
                                tabParamName,
                                location,
                            })}
                            isActive={() => isActiveItem(item, index)}
                            {...normalizeDataAttributes(item.dataAttributes)}
                        >
                            {typeof item.label === 'string'
                                ? formatMessage(item.label)
                                : item.label}
                        </NavLink>
                    </Nav.Item>
                ))}
            </Nav>

            {right}
        </div>
    );
};

export default PageNav;
