import {
    createRef,
    forwardRef,
    useImperativeHandle,
    useRef,
    useState,
} from 'react';

import { Loader2 } from 'lucide-react';

import { Button } from '@/components/ui/button';
import { SystemWindowDialog } from '@/components/ui/system-window-dialog';
import { toast } from '@/componentsRoot/ToastRoot';
import { Lang } from '@/lang/Lang';

import { ImageEditorCanvas } from './components/ImageEditorCanvas';
import { ImageEditorControls } from './components/ImageEditorControls';
import { ImageEditorToolbar } from './components/ImageEditorToolbar';
import { useImageEditor } from './hooks/useImageEditor';
import { getCroppedImg } from './utils/cropImage';

type OpenParams = {
    imageUrl: string;
    onSave: (base64: string) => void;
}

type ImageEditorRefType = {
    open: (params: OpenParams) => void;
    close: () => void;
}

export const imageEditorRef = createRef<ImageEditorRefType>();

export const ImageEditor = forwardRef<ImageEditorRefType, {}>((_, ref) => {
    const [open, setOpen] = useState(false);
    const editor = useImageEditor();
    const onSaveRef = useRef<((base64: string) => void) | null>(null);

    const handleClose = () => {
        setOpen(false);
        editor.cleanup();
        onSaveRef.current = null;
    };

    useImperativeHandle(ref, () => ({
        open: (params: OpenParams) => {
            onSaveRef.current = params.onSave;
            setOpen(true);
            void editor.load(params.imageUrl);
        },
        close: handleClose,
    }));

    const handleSave = async () => {
        if (!editor.objectUrl || !editor.croppedAreaPixels) {
            return;
        }
        editor.setProcessing(true);
        try {
            const base64 = await getCroppedImg(
                editor.objectUrl,
                editor.croppedAreaPixels,
                {
                    rotation: editor.rotation,
                    flipH: editor.flipH,
                    flipV: editor.flipV,
                    brightness: editor.adjust.brightness,
                    contrast: editor.adjust.contrast,
                    saturate: editor.adjust.saturate,
                    mimeType: editor.mimeType.current,
                },
            );
            onSaveRef.current?.(base64);
            handleClose();
        } catch {
            toast.error(Lang.key('image_editor_save_error'));
        } finally {
            editor.setProcessing(false);
        }
    };

    const busy = editor.loading || editor.processing;

    return (
        <SystemWindowDialog
            open={open}
            onOpenChange={(next) => {
                if (!next) {
                    handleClose();
                } else {
                    setOpen(next);
                }
            }}
            title={Lang.key('image_editor')}
            width="80vw"
            height="80vh"
            allowFullscreen
            bodyClassName="p-0 overflow-hidden flex flex-col"
            footer={
                <>
                    <Button
                        variant="outline"
                        type="button"
                        disabled={editor.processing}
                        onClick={handleClose}
                    >
                        {Lang.key('cancel')}
                    </Button>
                    <Button
                        type="button"
                        disabled={busy || !editor.croppedAreaPixels}
                        onClick={() => {
                            void handleSave();
                        }}
                    >
                        {editor.processing && (
                            <Loader2 className="size-4 animate-spin" />
                        )}
                        {Lang.key('save')}
                    </Button>
                </>
            }
        >
            <ImageEditorToolbar
                aspect={editor.aspect}
                flipH={editor.flipH}
                flipV={editor.flipV}
                disabled={busy || !editor.objectUrl}
                onRotate90={editor.rotate90}
                onFlipH={editor.toggleFlipH}
                onFlipV={editor.toggleFlipV}
                onSelectAspect={editor.selectAspect}
                onReset={editor.reset}
            />

            {editor.loadError ? (
                <div className="flex flex-1 items-center justify-center bg-neutral-900 px-6 text-center text-sm text-white/80">
                    {Lang.key('image_editor_load_error')}
                </div>
            ) : editor.loading || !editor.objectUrl ? (
                <div className="flex flex-1 items-center justify-center bg-neutral-900 text-white">
                    <Loader2 className="size-6 animate-spin" />
                </div>
            ) : (
                <ImageEditorCanvas
                    image={editor.objectUrl}
                    crop={editor.crop}
                    zoom={editor.zoom}
                    rotation={editor.rotation}
                    aspect={editor.aspect}
                    flipH={editor.flipH}
                    flipV={editor.flipV}
                    brightness={editor.adjust.brightness}
                    contrast={editor.adjust.contrast}
                    saturate={editor.adjust.saturate}
                    onCropChange={editor.setCrop}
                    onZoomChange={editor.setZoom}
                    onRotationChange={editor.setRotation}
                    onCropComplete={editor.onCropComplete}
                />
            )}

            <ImageEditorControls
                zoom={editor.zoom}
                rotation={editor.rotation}
                brightness={editor.adjust.brightness}
                contrast={editor.adjust.contrast}
                saturate={editor.adjust.saturate}
                disabled={busy || !editor.objectUrl}
                onZoomChange={editor.setZoom}
                onRotationChange={editor.setRotation}
                onBrightnessChange={editor.setBrightness}
                onContrastChange={editor.setContrast}
                onSaturateChange={editor.setSaturate}
            />
        </SystemWindowDialog>
    );

});
