import { useDebounceFn } from '@vueuse/core';
import { ref, toValue, watch, type MaybeRefOrGetter, type Ref } from 'vue';
import {
    isPlatePreviewReady,
    plateGenerationFingerprint,
    type PlatePreviewGenerationFields,
} from '@/utils/platePreview';

export type PlateGeneratorPreviewFields = PlatePreviewGenerationFields;

export interface UsePlateGeneratorPreviewUrlOptions {
    initialUrl?: string | null;
}

export function usePlateGeneratorPreviewUrl(
    fields: MaybeRefOrGetter<PlateGeneratorPreviewFields>,
    previewRoute: string,
    options: UsePlateGeneratorPreviewUrlOptions = {},
): { previewUrl: Ref<string | null>; isPreviewLoading: Ref<boolean> } {
    const { initialUrl = null } = options;

    const previewUrl = ref<string | null>(null);
    const isPreviewLoading = ref(false);
    let requestVersion = 0;
    let lastGenerationFingerprint: string | null = null;

    function buildPreviewUrl(values: PlateGeneratorPreviewFields): string | null {
        if (!isPlatePreviewReady(values)) {
            return null;
        }

        const params = new URLSearchParams({
            text: values.combination,
            state: values.state,
            frame: values.frame ? '1' : '0',
            display_state: values.display_state ? '1' : '0',
            display_position: values.display_position,
            width: values.width,
        });

        if (values.background_id !== null) {
            params.set('background_id', String(values.background_id));
        }

        if (values.characters_id !== null) {
            params.set('characters_id', String(values.characters_id));
        }

        if (values.category_id !== null) {
            params.set('category_id', String(values.category_id));
        }

        params.set('_', String(Date.now()));

        return `${previewRoute}?${params.toString()}`;
    }

    function clearPreview(): void {
        requestVersion += 1;
        previewUrl.value = null;
        isPreviewLoading.value = false;
        lastGenerationFingerprint = null;
    }

    function requestPreview(): void {
        const values = toValue(fields);
        const url = buildPreviewUrl(values);

        if (url === null) {
            clearPreview();

            return;
        }

        const fingerprint = plateGenerationFingerprint(values);

        lastGenerationFingerprint = fingerprint;

        const version = ++requestVersion;
        isPreviewLoading.value = true;

        const probe = new Image();
        probe.onload = () => {
            if (version === requestVersion) {
                previewUrl.value = url;
                isPreviewLoading.value = false;
            }
        };
        probe.onerror = () => {
            if (version === requestVersion) {
                isPreviewLoading.value = false;
            }
        };
        probe.src = url;
    }

    const refreshPreviewDebounced = useDebounceFn(() => requestPreview(), 350);

    watch(
        () => {
            const values = toValue(fields);

            if (!isPlatePreviewReady(values)) {
                return null;
            }

            return plateGenerationFingerprint(values);
        },
        (fingerprint) => {
            if (fingerprint === null) {
                clearPreview();

                return;
            }

            if (fingerprint === lastGenerationFingerprint && previewUrl.value !== null) {
                return;
            }

            const isFirstLoadWithSavedImage =
                lastGenerationFingerprint === null && initialUrl !== null && previewUrl.value === null;

            if (isFirstLoadWithSavedImage) {
                lastGenerationFingerprint = fingerprint;
                previewUrl.value = initialUrl;

                return;
            }

            isPreviewLoading.value = true;
            refreshPreviewDebounced();
        },
        { immediate: true },
    );

    return { previewUrl, isPreviewLoading };
}
