import React, {
    ComponentProps,
    DetailedHTMLProps,
    HTMLAttributes,
    ReactNode,
} from "react";
import { twMerge } from "tailwind-merge";
import CheckMarkSVG from "../svgs/CheckMarkSVG";
import Stack from "../layout/Stack";
import Row from "../layout/Row";
import { Info } from "lucide-react";
import Span from "../layout/Span";

export type CheckboxProps = Omit<
    React.DetailedHTMLProps<
        React.HTMLAttributes<HTMLDivElement>,
        HTMLDivElement
    >,
    "title"
> & {
    title?: string | ReactNode;
    wrapperProps?: DetailedHTMLProps<
        HTMLAttributes<HTMLDivElement>,
        HTMLDivElement
    >;
    label?: string | ReactNode;
    labelProps?: React.DetailedHTMLProps<
        React.HTMLAttributes<HTMLDivElement>,
        HTMLDivElement
    >;
    defaultChecked?: boolean;
    wrapperClassName?: string;
    setChecked?: React.Dispatch<React.SetStateAction<boolean>>;
    checked?: boolean;
    readOnly?: boolean;
    noLabel?: boolean;
    size?: number;
    changeHandler?: (value: boolean) => void;
    info?: string | ReactNode;
    wrapperWrapperProps?: ComponentProps<typeof Stack>;
};

/**
 * # Checkbox Component
 * @className twui-checkbox
 * @className twui-checkbox-checked
 * @className twui-checkbox-unchecked
 */
export default function Checkbox({
    wrapperProps,
    label,
    labelProps,
    size,
    wrapperClassName,
    defaultChecked,
    setChecked: externalSetChecked,
    readOnly,
    checked: externalChecked,
    changeHandler,
    info,
    wrapperWrapperProps,
    noLabel,
    title,
    ...props
}: CheckboxProps) {
    const finalSize = size || 20;

    const [checked, setChecked] = React.useState(
        defaultChecked || externalChecked || false,
    );

    const finalTitle = title
        ? title
        : `Checkbox-${Math.round(Math.random() * 100000)}`;

    React.useEffect(() => {
        if (typeof externalChecked == "undefined") return;
        setChecked(externalChecked);
    }, [externalChecked]);

    React.useEffect(() => {
        changeHandler?.(checked);
    }, [checked]);

    return (
        <Stack
            {...wrapperWrapperProps}
            className={twMerge("gap-1.5", wrapperWrapperProps?.className)}
        >
            <div
                {...wrapperProps}
                className={twMerge(
                    "flex items-start md:items-center gap-2 flex-wrap md:flex-nowrap",
                    readOnly ? "opacity-70 pointer-events-none" : "",
                    wrapperClassName,
                    wrapperProps?.className,
                )}
                onClick={() => {
                    setChecked(!checked);
                    externalSetChecked?.(!checked);
                }}
            >
                <div
                    {...props}
                    className={twMerge(
                        "flex items-center justify-center p-[3px] rounded-default",
                        checked
                            ? "bg-primary twui-checkbox-checked text-white outline-slate-400"
                            : "dark:outline-white/50 outline-2 -outline-offset-2 twui-checkbox-unchecked",
                        "twui-checkbox",
                        props.className,
                    )}
                    style={{
                        minWidth: finalSize + "px",
                        width: finalSize + "px",
                        height: finalSize + "px",
                        ...props.style,
                    }}
                >
                    {checked && <CheckMarkSVG />}
                </div>
                {!noLabel && (
                    <Stack className="gap-0.5">
                        <div
                            {...labelProps}
                            className={twMerge(
                                "select-none whitespace-normal md:whitespace-nowrap",
                                labelProps?.className,
                            )}
                        >
                            {label || finalTitle}
                        </div>
                    </Stack>
                )}
            </div>
            {info && (
                <Row className="gap-1 flex-nowrap" title={info.toString()}>
                    <Info size={13} className="opacity-40 min-w-[20px]" />
                    <Span size="smaller" className="opacity-70">
                        {info}
                    </Span>
                </Row>
            )}
        </Stack>
    );
}
