import { OSStatPanelProps } from "./props";
import { OSPanel } from "../panel";
import { useCallback, useEffect, useRef, useState } from "react";
import React from "react";
import { OSIcon } from "../icon";
import { Icon } from "../../types/icon";
import { OSLabel, OSLabelProps } from "../label";
import { Skeleton } from "primereact/skeleton";
import { Tooltip } from "primereact/tooltip";
import { FAIdentifier } from "../../types/fa-icons";
import { classNames } from "primereact/utils";
import { useExposableState } from "../../hooks";

export function OSStatPanel({
    className,
    value,
    icon,
    onFilter,
    description,
    tooltip,
    tooltipOptions,
    filtered,
    setFiltered,
    loading,
    href,
    target,
    options,
    ...props }: OSStatPanelProps) {

    const labelFilter: OSLabelProps = { leadingIcon: "filter", label: "Filter" };
    const labelRemoveFilter: OSLabelProps = { leadingIcon: "filter-circle-xmark", label: "Remove Filter" };
    const labelFiltered: OSLabelProps = { leadingIcon: "filter", label: "Filtered" };

    const elementRef = useRef<any>(null);
    const valueRef = useRef<HTMLDivElement>(null);

    //Variable size of value text to ensure always visible.
    const resizeText = useCallback(() => {
        const element = valueRef.current;
        if (!element) return;

        const container = element.parentElement;
        if (!container) return;

        element.style.fontSize = getComputedStyle(element).getPropertyValue("--size-value");
        let fontSize = parseFloat(getComputedStyle(element).fontSize);

        while (element.scrollWidth > container.clientWidth && fontSize > 10) {
            fontSize -= 0.5;
            element.style.fontSize = fontSize + "px";
        }
    }, []);

    //Trigger resize when text value changes
    useEffect(resizeText, [value])

    //Trigger resize on element resize.
    useEffect(() => {
        if (!valueRef.current) {
            return;
        }
        const valueObserver = new ResizeObserver(resizeText);
        valueObserver.observe(valueRef.current)

        return () => valueObserver.disconnect();
    }, []);


    const filterable = onFilter != null;
    const [isFiltered, setIsFiltered] = useExposableState(false, filtered, setFiltered);

    if (typeof icon === "string") {
        icon = { identifier: icon as FAIdentifier }
    }

    const [filterText, setFilterText] = useState<OSLabelProps>(labelFilter);

    const filter = useCallback(() => {
        const newState = !isFiltered;
        onFilter?.(newState);
        setFilterText(newState ? labelRemoveFilter : labelFilter)
        setIsFiltered(newState);
    }, [onFilter, isFiltered]);

    const handleClick = useCallback(() => {
        if (onFilter) filter();
        if (href) window.open(href, target ?? "_self");
    }, [onFilter, filter, href, target]);

    return (<>
        <OSPanel {...props}
            onClick={(onFilter || href) ? handleClick : undefined}
            onMouseEnter={() => {
                if (!isFiltered) {
                    setFilterText(labelFilter)
                } else {
                    setFilterText(labelRemoveFilter)
                }
            }}
            onMouseLeave={() => {
                if (!isFiltered) {
                    setFilterText(labelFilter)
                } else {
                    setFilterText(labelFiltered)
                }
            }}
            className={classNames(
                "os-stat-panel",
                filterable && "filterable",
                isFiltered && "filtered",
                href && "cursor-pointer",
                className
            )}>
            <div ref={elementRef} className="stat-panel-content">
                {/* Icon */}
                <div className="flex stat-panel-icon">
                    {React.isValidElement(icon)
                        ? <div>{icon}</div>
                        : <OSIcon weight="thin" {...icon as Icon} {...(!options?.showIconTooltip) && { tooltip: null }} />}
                    {description && <div className="relative">
                        {/* Description badge */}
                        <div className="absolute">
                            <OSIcon
                                identifier="circle-info"
                                weight="solid"
                                size={"1rem"}
                                colour="var(--os-accent)"
                                tooltip={description}
                            />
                        </div>
                    </div>}
                </div>
                {/* Value */}
                {loading || value === undefined ? (
                    <div className="px-2 w-full">
                        <Skeleton height={"var(--size-value)"} />
                    </div>
                ) : (
                    <div className="flex place-content-center stat-panel-value" ref={valueRef}>
                        <OSLabel label={typeof value === "number"
                            ? new Intl.NumberFormat("en-ZA").format(value ?? 0)
                            : value}
                            colour="var(--colour-corporate-blue)"
                            style={{ lineHeight: 1, userSelect: "none" }}
                            weight={200}
                        />
                    </div>
                )}
            </div>
            {filterable && <>
                <OSIcon className="filter-icon absolute top-0 right-0 m-1" identifier="filter" colour="var(--colour-linework)" />
                <div className="filter-banner">
                    <OSLabel {...filterText} />
                </div>
            </>}
        </OSPanel>

        {tooltip && (elementRef !== null) && <Tooltip target={elementRef as React.RefObject<HTMLElement>} mouseTrack {...tooltipOptions}>{tooltip}</Tooltip>}
    </>);
}