import React, { useCallback, useEffect, useRef, useState } from "react";
import {
    FieldHelperText,
    FieldProps,
    getIconForProperty,
    LabelWithIconAndTooltip,
    PropertyOrBuilder,
    randomString,
    ResolvedArrayProperty,
    ResolvedStringProperty,
    useAuthController,
    useStorageSource
} from "../../index";
import { cls, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, fieldBackgroundMixin, IconButton, CloseIcon } from "@firecms/ui";
import type { FireCMSEditorProps } from "../../editor";
import { resolveProperty, resolveStorageFilenameString, resolveStoragePathString } from "../../util";
import { isImageFile, resizeImage } from "../../util/useStorageUploadController";
import { lazyEager } from "../../util/lazy_eager";
import { CircularProgressCenter } from "../../components/CircularProgressCenter";

const FireCMSEditor = lazyEager<typeof import("../../editor/editor")["FireCMSEditor"]>(() => import("../../editor/editor"), "FireCMSEditor");

interface MarkdownEditorFieldProps {
    highlight?: { from: number, to: number };
    editorProps?: Partial<FireCMSEditorProps>
}

export function MarkdownEditorFieldBinding({
    property,
    propertyKey,
    value,
    setValue,
    includeDescription,
    showError,
    error,
    minimalistView,
    disabled: disabledProp,
    isSubmitting,
    context,
    customProps,
}: FieldProps<string, MarkdownEditorFieldProps>) {

    const authController = useAuthController();
    const disabled = disabledProp || isSubmitting;
    const highlight = customProps?.highlight;
    const editorProps = customProps?.editorProps;
    const storageSource = useStorageSource();
    const storage = property.storage;

    const entityValues = context.values;
    const entityId = context.entityId;
    const path = context.path;

    const [fieldVersion, setFieldVersion] = useState(0);
    const internalValue = useRef<string | null>(value);

    const onContentChange = useCallback((content: string) => {
        if (content === value || ((value === null || value === undefined) && content === "")) {
            return;
        }
        internalValue.current = content;
        setValue(content);
    }, [setValue, value]);

    useEffect(() => {
        if (internalValue.current !== value) {
            internalValue.current = value;
            setFieldVersion(v => v + 1);
        }
    }, [value]);

    const resolvedProperty = resolveProperty({
        propertyOrBuilder: property as PropertyOrBuilder<string>,
        values: entityValues,
        authController
    }) as ResolvedStringProperty | ResolvedArrayProperty<string[]>;

    const fileNameBuilder = useCallback(async (file: File) => {
        if (storage?.fileName) {
            const fileName = await resolveStorageFilenameString({
                input: storage.fileName,
                storage,
                values: entityValues,
                entityId,
                path,
                property: resolvedProperty,
                file,
                propertyKey
            });
            if (!fileName || fileName.length === 0) {
                throw Error("You need to return a valid filename");
            }
            return fileName;
        }
        return randomString() + "_" + file.name;
    }, [entityId, entityValues, path, resolvedProperty, propertyKey, storage]);

    const storagePathBuilder = useCallback((file: File) => {
        if (!storage) return "/";
        const resolvedProperty = resolveProperty({
            propertyOrBuilder: property,
            values: entityValues,
            authController
        }) as ResolvedStringProperty | ResolvedArrayProperty<string[]>;
        return resolveStoragePathString({
            input: storage.storagePath,
            storage,
            values: entityValues,
            entityId,
            path,
            property: resolvedProperty,
            file,
            propertyKey
        }) ?? "/";
    }, [entityId, entityValues, path, property, propertyKey, storage]);

    // Extract markdown config from property - can be boolean or object
    const markdownConfig = typeof property.markdown === 'object' ? property.markdown : undefined;

    const handleImageUpload = async (file: File) => {
        const imageResize = storage?.imageResize;
        const legacyCompression = storage?.imageCompression;
        if ((imageResize || legacyCompression) && isImageFile(file)) {
            file = await resizeImage(file, imageResize, legacyCompression);
        }

        const storagePath = storagePathBuilder(file);
        const fileName = await fileNameBuilder(file);
        const result = await storageSource.uploadFile({
            file,
            fileName,
            path: storagePath,
        });
        const downloadConfig = await storageSource.getDownloadURL(result.path);
        const url = downloadConfig.url;
        if (!url) {
            throw new Error("Error uploading image");
        }
        return url;
    };

    const editor = (
        <React.Suspense fallback={<CircularProgressCenter />}>
            <FireCMSEditor
                key={context.formex.version + fieldVersion}
                content={value}
                onMarkdownContentChange={onContentChange}
                version={context.formex.version + fieldVersion}
                highlight={highlight}
                disabled={disabled}
                markdownConfig={markdownConfig}
                handleImageUpload={handleImageUpload}
                {...editorProps}
            />
        </React.Suspense>
    );

    if (minimalistView)
        return (
            <>
                {editor}
            </>
        );

    return (
        <>
            <div className="flex items-center w-full">
                <LabelWithIconAndTooltip
                    propertyKey={propertyKey}
                    icon={getIconForProperty(property, "small")}
                    required={property.validation?.required}
                    title={property.name}
                    className={"h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"} />
                <div className="flex-grow"/>
                {(property.nullable || property.clearable) && !disabled && (
                    <IconButton
                        size="small"
                        onClick={(e) => {
                            e.stopPropagation();
                            e.preventDefault();
                            setValue(null);
                        }}
                    >
                        <CloseIcon size={"small"}/>
                    </IconButton>
                )}
            </div>
            <div
                className={cls("rounded-md", fieldBackgroundMixin, disabled ? fieldBackgroundDisabledMixin : fieldBackgroundHoverMixin)}>
                {editor}
            </div>
            <FieldHelperText includeDescription={includeDescription}
                showError={showError}
                error={error}
                property={property} />
        </>

    );

}
