// @ts-ignore
import React, {Component} from "react";
import {
    findNodeHandle,
    type HostComponent,
    type NativeMethods,
    NativeModules,
    requireNativeComponent,
    StyleSheet,
    View
} from "react-native";
import type {EnumDrawingLayerId} from "./EnumDrawingLayerId";
import type {Quadrilateral, ImageData} from "../core";
import type {ImageEditorViewNativeProps} from "./DynamsoftImageEditorViewNativeComponent";

const ComponentName = "DynamsoftImageEditorView";

// @ts-ignore Check whether __turboModuleProxy exists, it may not
const isTurboModuleEnabled = global.__turboModuleProxy != null;

const NativeImageEditorView: HostComponent<ImageEditorViewNativeProps> = isTurboModuleEnabled ?
    require("./DynamsoftImageEditorViewNativeComponent").default :
    requireNativeComponent(ComponentName)

const ImageEditorViewCommands = isTurboModuleEnabled ?
    require("./DynamsoftImageEditorViewNativeComponent").Commands :
    null

// Keep module usage for JSI install + getSelectedQuad until selected-quad query is migrated to a command/event flow.
const ImageEditorViewModule = isTurboModuleEnabled ?
    require("./NativeDynamsoftImageEditorViewModule").default :
    NativeModules.DynamsoftImageEditorView;

let isInstalled = false
const installMethods = () => {
    if (!isInstalled) {
        ImageEditorViewModule.install()
        isInstalled = true
    }
}

declare var global: {
    editorView_setOriginalImage: (viewTag: number, imageData: ImageData) => void;
};

type RefType = React.Component<ImageEditorViewNativeProps> & Readonly<NativeMethods>;

/**
 * The ImageEditorView class is a React Component for image editing that wraps the native ImageEditorView.
 * It encapsulates interactions with the native view and provides functionality
 * to set images and edit quadrilaterals.
 * @prop CameraViewNativeProps
 * @see {@link CameraViewNativeProps}
 * @see {@link CameraEnhancer.setCameraView}
 * @hideconstructor
 */
export class ImageEditorView extends Component<ImageEditorViewNativeProps, any> {
    // A Ref object pointing to the native ImageEditorView
    private readonly nativeImageEditorViewRef: React.RefObject<RefType | null> = React.createRef<RefType>();
    private drawingQuads: Array<Quadrilateral> | null | undefined;

    /** @internal */
    public get nativeCameraViewHandle(): number | null {
        return findNodeHandle(this.nativeImageEditorViewRef.current);
    }

    /**
     * Sets the original image in the native image editor.
     * @param imageData The {@link ImageData} Object to be set as the original image.
     */
    public setOriginalImage(imageData: ImageData) {
        installMethods();
        if (typeof global.editorView_setOriginalImage !== 'function') {
            return;
        }
        if (this.nativeCameraViewHandle != null) {
            global.editorView_setOriginalImage(this.nativeCameraViewHandle!, imageData);
        }
    }

    /**
     * Updates the quadrilaterals in the editor for a specific drawing layer.
     * @param quads The quadrilaterals to set, or null/undefined to clear them. The coordinate base of the point is "image".
     * @param layerId The ID of the drawing layer to update.
     * @returns A promise that resolves once the operation completes.
     */
    public async setQuads(quads: Quadrilateral[] | null | undefined, layerId: EnumDrawingLayerId | number): Promise<void> {
        const viewRef = this.nativeImageEditorViewRef.current;
        const viewTag = this.nativeCameraViewHandle;
        if (viewRef != null && viewTag != null) {
            this.drawingQuads = quads;
            // ImageEditorView is still handled by the legacy/iOS manager path in this package,
            // so module dispatch is the reliable route to reach native setQuads today.
            if (ImageEditorViewModule?.setQuads != null) {
                await ImageEditorViewModule.setQuads(viewTag, quads ?? [], Number(layerId));
            } else if (ImageEditorViewCommands != null) {
                ImageEditorViewCommands.setQuads(viewRef, (quads ?? []) as any, Number(layerId));
            }
        }
    }

    /**
     * Retrieves the currently selected quadrilateral from the editor.
     * @returns A promise that resolves to the selected quadrilateral, or first Quadrilateral if none is selected.
     */
    public async getSelectedQuad(): Promise<Quadrilateral | null> {
        if (this.nativeCameraViewHandle != null) {
            let selectedQuad = await ImageEditorViewModule.getSelectedQuad(this.nativeCameraViewHandle!);
            if(selectedQuad) {
                return selectedQuad;
            } else if(this.drawingQuads && this.drawingQuads.length > 0) {
                selectedQuad = this.drawingQuads[0]
            }
            return selectedQuad;
        } else {
            return null;
        }
    }

    public render(): React.ReactNode {
        return (
            <View style={[styles.blackBg, this.props?.style]}>
                <NativeImageEditorView
                    collapsable={false}
                    style={StyleSheet.absoluteFill}
                    ref={this.nativeImageEditorViewRef}
                />
                {this.props?.children}
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: "center",
        justifyContent: "center"
    },
    blackBg: {
        backgroundColor: "black"
    }
});
