import Button from "../layout/Button";
import Stack from "../layout/Stack";
import {
    File,
    FileArchive,
    FilePlus,
    FilePlus2,
    ImagePlus,
    X,
} from "lucide-react";
import React, { DetailedHTMLProps } from "react";
import Card from "../elements/Card";
import Span from "../layout/Span";
import Center from "../layout/Center";
import imageInputToBase64, {
    FileInputToBase64FunctionReturn,
} from "../utils/form/fileInputToBase64";
import { twMerge } from "tailwind-merge";
import fileInputToBase64 from "../utils/form/fileInputToBase64";
import Row from "../layout/Row";

type ImageUploadProps = DetailedHTMLProps<
    React.HTMLAttributes<HTMLDivElement>,
    HTMLDivElement
> & {
    onChangeHandler?: (
        imgData: FileInputToBase64FunctionReturn | undefined
    ) => any;
    fileInputProps?: DetailedHTMLProps<
        React.InputHTMLAttributes<HTMLInputElement>,
        HTMLInputElement
    >;
    placeHolderWrapper?: DetailedHTMLProps<
        React.HTMLAttributes<HTMLDivElement>,
        HTMLDivElement
    >;
    previewImageWrapperProps?: DetailedHTMLProps<
        React.HTMLAttributes<HTMLDivElement>,
        HTMLDivElement
    >;
    previewImageProps?: DetailedHTMLProps<
        React.ImgHTMLAttributes<HTMLImageElement>,
        HTMLImageElement
    >;
    label?: string;
    disablePreview?: boolean;
    allowedRegex?: RegExp;
    externalSetFile?: React.Dispatch<
        React.SetStateAction<FileInputToBase64FunctionReturn | undefined>
    >;
};

/**
 * @note use the `onChangeHandler` prop to grab the parsed base64 image object
 */
export default function FileUpload({
    onChangeHandler,
    fileInputProps,
    placeHolderWrapper,
    previewImageWrapperProps,
    previewImageProps,
    label,
    disablePreview,
    allowedRegex,
    externalSetFile,
    ...props
}: ImageUploadProps) {
    const [file, setFile] = React.useState<
        FileInputToBase64FunctionReturn | undefined
    >(undefined);
    const inputRef = React.useRef<HTMLInputElement>();

    return (
        <Stack
            {...props}
            className={twMerge("w-full h-[300px]", props?.className)}
        >
            <input
                type="file"
                className={twMerge("hidden", fileInputProps?.className)}
                {...fileInputProps}
                onChange={(e) => {
                    const inputFile = e.target.files?.[0];

                    if (!inputFile) return;

                    fileInputToBase64({ inputFile, allowedRegex }).then(
                        (res) => {
                            setFile(res);
                            externalSetFile?.(res);
                            onChangeHandler?.(res);
                            fileInputProps?.onChange?.(e);
                        }
                    );
                }}
                ref={inputRef as any}
            />

            {file ? (
                <Card
                    className="w-full relative h-full items-center justify-center overflow-hidden"
                    {...previewImageWrapperProps}
                >
                    {disablePreview ? (
                        <Span className="opacity-50" size="small">
                            Image Uploaded!
                        </Span>
                    ) : file.fileType?.match(/image/i) ? (
                        <img
                            src={file.fileBase64Full}
                            className="w-full object-contain overflow-hidden"
                            {...previewImageProps}
                        />
                    ) : (
                        <Row>
                            <FileArchive size={36} strokeWidth={1} />
                            <Stack className="gap-0">
                                <Span>{file.file?.name || file.fileName}</Span>
                                <Span size="smaller" className="opacity-70">
                                    {file.fileType}
                                </Span>
                            </Stack>
                        </Row>
                    )}
                    <Button
                        variant="ghost"
                        className={twMerge(
                            "absolute p-2 top-2 right-2 z-20 bg-white dark:bg-black",
                            "hover:bg-white dark:hover:bg-black"
                        )}
                        onClick={(e) => {
                            setFile(undefined);
                            externalSetFile?.(undefined);
                            onChangeHandler?.(undefined);
                        }}
                    >
                        <X className="text-slate-950 dark:text-white" />
                    </Button>
                </Card>
            ) : (
                <Card
                    className={twMerge(
                        "w-full h-full cursor-pointer hover:bg-slate-100 dark:hover:bg-white/20",
                        placeHolderWrapper?.className
                    )}
                    onClick={(e) => {
                        inputRef.current?.click();
                        placeHolderWrapper?.onClick?.(e);
                    }}
                    {...placeHolderWrapper}
                >
                    <Center>
                        <Stack className="items-center gap-2">
                            <FilePlus2 className="text-slate-400" />
                            <Span size="smaller" variant="faded">
                                {label || "Click to Upload File"}
                            </Span>
                        </Stack>
                    </Center>
                </Card>
            )}
        </Stack>
    );
}