import { Colors } from '@/constants/theme';
import { isPromise } from '@/utils/tsutils';
import { ActivityIndicator, Icon } from '@ant-design/react-native';
import { type IconNames } from '@ant-design/react-native/lib/icon';
import { clsx } from 'clsx';
import { Href, Link } from 'expo-router';
import React, { useEffect, useState } from 'react';
import { Pressable, Text, View, ViewStyle } from 'react-native';

interface UIButtonProps {
    children?: string | React.ReactNode;
    title?: string | React.ReactNode;
    onPress?: () => PromiseLike<unknown> | unknown;
    disabled?: boolean;
    className?: string;
    textClassName?: string;
    href?: Href;
    type?: 'primary' | 'second' | 'link';
    icon?: IconNames | React.ReactNode;
    style?: ViewStyle;
    loading?: boolean;
}

type ButtonType = UIButtonProps['type'];

function getIconColor(type: ButtonType, disabled: boolean) {
    if (disabled) return Colors['on-surface']['variant'];
    if (type === 'primary') return '#fff';
    if (type === 'second') return Colors.secondary.DEFAULT;
    return Colors.primary.DEFAULT;
}

function ButtonLabel({
    type,
    disabled,
    textClassName,
    children,
    loading,
}: {
    type: ButtonType;
    disabled: boolean;
    textClassName?: string;
    children: React.ReactNode;
    loading: boolean;
}) {
    const labelClass = clsx(textClassName, 'text-sm font-semibold', {
        'text-on-primary': !disabled && type === 'primary',
        'text-primary': !disabled && type !== 'primary' && type !== 'second',
        'text-secondary': !disabled && type === 'second',
        'text-on-surface-variant/65 font-normal': disabled,
    });

    if (!loading) return <Text className={labelClass}>{children}</Text>;
    return (
        <View className="flex-row justify-center items-center">
            <ActivityIndicator color={disabled ? '#888' : Colors['on-primary']['DEFAULT']} />
            <Text className={labelClass}>{children}</Text>
        </View>
    );
}

export default function UIButton({
    onPress,
    href,
    type,
    icon,
    className,
    style,
    disabled,
    children,
    title,
    textClassName,
    loading,
}: UIButtonProps) {
    const [busy, setBusy] = useState(loading);
    const isDisabled = Boolean(disabled || busy);

    useEffect(() => {
        setBusy(loading);
    }, [loading]);

    const label = children ?? title;

    const handlePress = () => {
        if (isDisabled) return;
        const res = onPress?.();
        if (isPromise(res)) {
            setBusy(true);
            (res as Promise<unknown>).finally(() => setBusy(false));
        }
    };

    const inner = (
        <Pressable
            className={clsx(
                'flex-row justify-center items-center rounded-xl py-1.5 border-2 opacity-100 active:opacity-75 active:scale-95',
                className,
                {
                    'bg-primary border-primary': type === 'primary',
                    'bg-surface border-primary/25': !type,
                    'bg-surface border-on-surface/25': type === 'second',
                    'bg-transparent border-transparent': type === 'link',
                    'bg-primary-fixed-dim border-primary-fixed-dim': isDisabled && type === 'primary',
                    'bg-gray-300 border-gray-300': isDisabled && !type,
                    'bg-gray-400 border-gray-200': isDisabled && type === 'second',
                }
            )}
            disabled={isDisabled}
            onPress={handlePress}
            style={style}
        >
            {typeof icon === 'string' ? (
                <Icon
                    name={icon as IconNames}
                    size={20}
                    style={{ marginRight: 4, color: getIconColor(type, isDisabled) }}
                />
            ) : (
                icon
            )}
            {typeof label === 'string' ? (
                <ButtonLabel type={type} disabled={isDisabled} loading={!!busy} textClassName={textClassName}>
                    {label}
                </ButtonLabel>
            ) : (
                label
            )}
        </Pressable>
    );

    if (typeof href !== 'undefined') {
        return (
            <Link href={href} asChild>
                {inner}
            </Link>
        );
    }
    return inner;
}
