import {
    AnchorHTMLAttributes,
    ButtonHTMLAttributes,
    DetailedHTMLProps,
    HTMLAttributeAnchorTarget,
    HTMLAttributes,
} from "react";
import { twMerge } from "tailwind-merge";
import Loading from "../elements/Loading";

/**
 * # Buttons
 * @className twui-button-general
 * @className twui-button-content-wrapper
 * @className twui-button-primary
 * @className twui-button-primary-outlined
 * @className twui-button-primary-ghost
 * @className twui-button-secondary
 * @className twui-button-secondary-outlined
 * @className twui-button-secondary-ghost
 * @className twui-button-accent
 * @className twui-button-accent-outlined
 * @className twui-button-accent-ghost
 * @className twui-button-gray
 * @className twui-button-gray-outlined
 * @className twui-button-gray-ghost
 */
export default function Button({
    href,
    target,
    variant,
    color,
    size,
    buttonContentProps,
    linkProps,
    beforeIcon,
    afterIcon,
    loading,
    ...props
}: DetailedHTMLProps<
    ButtonHTMLAttributes<HTMLButtonElement>,
    HTMLButtonElement
> & {
    variant?: "normal" | "ghost" | "outlined";
    color?:
        | "primary"
        | "secondary"
        | "accent"
        | "gray"
        | "error"
        | "warning"
        | "success";
    size?: "small" | "smaller" | "normal" | "large" | "larger";
    href?: string;
    target?: HTMLAttributeAnchorTarget;
    loading?: boolean;
    linkProps?: DetailedHTMLProps<
        AnchorHTMLAttributes<HTMLAnchorElement>,
        HTMLAnchorElement
    >;
    beforeIcon?: React.ReactNode;
    afterIcon?: React.ReactNode;
    buttonContentProps?: DetailedHTMLProps<
        HTMLAttributes<HTMLDivElement>,
        HTMLDivElement
    >;
}) {
    const finalClassName: string = (() => {
        if (variant == "normal" || !variant) {
            if (color == "primary" || !color)
                return twMerge(
                    "bg-blue-500 hover:bg-blue-600 text-white",
                    "twui-button-primary"
                );
            if (color == "secondary")
                return twMerge(
                    "bg-emerald-500 hover:bg-emerald-600 text-white",
                    "twui-button-secondary"
                );
            if (color == "accent")
                return twMerge(
                    "bg-violet-500 hover:bg-violet-600 text-white",
                    "twui-button-accent"
                );
            if (color == "gray")
                return twMerge(
                    "bg-slate-300 hover:bg-slate-200 text-slate-800",
                    "twui-button-gray"
                );
        } else if (variant == "outlined") {
            if (color == "primary" || !color)
                return twMerge(
                    "bg-transparent outline outline-1 outline-blue-500",
                    "text-blue-500 dark:text-blue-400 dark:outline-blue-300",
                    "twui-button-primary-outlined"
                );
            if (color == "secondary")
                return twMerge(
                    "bg-transparent outline outline-1 outline-emerald-500",
                    "text-emerald-500",
                    "twui-button-secondary-outlined"
                );
            if (color == "accent")
                return twMerge(
                    "bg-transparent outline outline-1 outline-violet-500",
                    "text-violet-500",
                    "twui-button-accent-outlined"
                );
            if (color == "gray")
                return twMerge(
                    "bg-transparent outline outline-1 outline-slate-300",
                    "text-slate-600 dark:text-white/60 dark:outline-white/30",
                    "twui-button-gray-outlined"
                );
        } else if (variant == "ghost") {
            if (color == "primary" || !color)
                return twMerge(
                    "bg-transparent outline-none p-2",
                    "text-blue-500",
                    "twui-button-primary-ghost"
                );
            if (color == "secondary")
                return twMerge(
                    "bg-transparent outline-none p-2",
                    "text-emerald-500",
                    "twui-button-secondary-ghost"
                );
            if (color == "accent")
                return twMerge(
                    "bg-transparent outline-none p-2",
                    "text-violet-500",
                    "twui-button-accent-ghost"
                );
            if (color == "gray")
                return twMerge(
                    "bg-transparent outline-none p-2",
                    "text-slate-600 dark:text-white/70",
                    "twui-button-gray-ghost"
                );
            if (color == "error")
                return twMerge(
                    "bg-transparent outline-none p-2",
                    "text-red-600 dark:text-red-400",
                    "twui-button-error-ghost"
                );
            if (color == "warning")
                return twMerge(
                    "bg-transparent outline-none p-2",
                    "text-yellow-600",
                    "twui-button-warning-ghost"
                );
            if (color == "success")
                return twMerge(
                    "bg-transparent outline-none p-2",
                    "text-emerald-600",
                    "twui-button-success-ghost"
                );
        }

        return "";
    })();

    const buttonComponent = (
        <button
            {...props}
            className={twMerge(
                "bg-blue-600 text-white text-base font-medium px-4 py-2 rounded",
                "flex items-center justify-center relative transition-all",
                "twui-button-general",
                size == "small" && "px-3 py-1.5 text-sm",
                size == "smaller" && "px-2 py-1 text-xs",
                size == "large" && "text-lg",
                size == "larger" && "px-5 py-3 text-xl",
                finalClassName,
                props.className,
                loading ? "pointer-events-none opacity-80" : "l"
            )}
        >
            <div
                {...buttonContentProps}
                className={twMerge(
                    "flex flex-row items-center gap-2 whitespace-nowrap",
                    loading ? "opacity-0" : "",
                    "twui-button-content-wrapper",
                    buttonContentProps?.className
                )}
            >
                {beforeIcon && beforeIcon}
                {props.children}
                {afterIcon && afterIcon}
            </div>

            {loading && (
                <Loading
                    className="absolute"
                    size={(() => {
                        switch (size) {
                            case "small":
                                return "small";
                            case "smaller":
                                return "smaller";

                            default:
                                return "normal";
                        }
                    })()}
                />
            )}
        </button>
    );

    if (href)
        return (
            <a {...linkProps} href={href} target={target}>
                {buttonComponent}
            </a>
        );
    return buttonComponent;
}
