import {
    downscaleImageQuality,
    setTemporaryVisualImage,
    storeImageToIndexedDb
} from './visual-similarity-search.js';

import {
    cameraHelperElementObject,
    checkIfCameraExists,
    closeLabelCamera,
    openLabelCamera,
    handleCloseCameraElements,
    handleOpenCameraElements,
    isDeviceMobileOrTablet,
    isIOS,
    setInitialCameraView
} from './camera-capture/camera-capture-helper.js';

import {
    athenaConfig,
    athenaConfigOptions
} from '../../../global/athena-config.js';

let cameraFacingMode = null;
let isCameraOpen = false;

const captureImage = () =>
{
    sessionStorage.removeItem('athenaVisualConversionChannel');
    sessionStorage.setItem('athenaVisualConversionChannel', 'camera');
    const {
        videoElement,
        previewImage,
        infoContainer
    } = cameraHelperElementObject();

    const canvas = document.createElement('canvas');
    canvas.width = videoElement.videoWidth;
    canvas.height = videoElement.videoHeight;

    canvas.getContext('2d')
        .drawImage(
            videoElement,
            0,
            0,
            canvas.width,
            canvas.height
        );

    const base64Image = canvas.toDataURL('image/png');

    downscaleImageQuality(
        base64Image,
        athenaConfigOptions.imageQuality,
        async (result) => {
            await setTemporaryVisualImage(result);
            await storeImageToIndexedDb(false, result);
            handleCloseCameraElements(true);

            previewImage.src = result;

            athenaConfigOptions.cropper?.destroy();
            infoContainer?.classList.add('athena-helper-hide');

            athenaConfigOptions.cropper = new window.Cropper(previewImage, {
                viewMode: 2,
                aspectRatio: 'Free',
                minContainerHeight: 300,
                minCanvasHeight: 300,
                autoCropArea: 0.99
            });
        });

    disableCamera();
};

const enableCamera = async (
    facingMode,
    initialOpen = true
) =>
{
    const { videoElement, captureButton } = cameraHelperElementObject();

    if (!await checkCameraPermission()) return;

    try {
        const constraints = {
            video: {
                facingMode,
                width: { min: 1280, ideal: 1920, max: 2560 },
                height: { min: 720, ideal: 1080, max: 1440 }
            },
            audio: false
        };

        videoElement.srcObject = await navigator.mediaDevices.getUserMedia(constraints);
        handleOpenCameraElements();

        videoElement.onloadedmetadata = () => {
            videoElement.play().catch(console.warn);
        };

        if (initialOpen) {
            captureButton?.removeEventListener('click', captureImage);
            captureButton?.addEventListener('click', captureImage);
        }
    } catch (error) {
        handleCloseCameraElements();
        console.error('Error enabling camera:', error);
    }
};

const handleOpenCamera = async (
    avoidListener = false,
    facingMode
) =>
{
    const {
        openCameraButton,
        infoContainer
    } = cameraHelperElementObject();

    cameraFacingMode = facingMode;

    if(avoidListener) {
        await enableCamera(
            facingMode,
            false
        );

        return;
    }

    if (isCameraOpen) return;

    const openCameraHandler = async () =>
    {
        await enableCamera(facingMode, true);
        infoContainer?.classList.add('athena-helper-hide');
        isCameraOpen = true;
    };

    openCameraButton?.removeEventListener('click', openCameraHandler);
    openCameraButton?.addEventListener('click', openCameraHandler);
};

const disableCamera = (
    close = true
) =>
{
    const { videoElement, infoContainer } = cameraHelperElementObject();
    if(
        !videoElement ||
        !videoElement?.srcObject
    ) return;

    videoElement.pause();
    videoElement.load();

    videoElement?.srcObject
        .getTracks()
        .forEach(track => {
            track.stop();
        });

    videoElement.srcObject = null;

    if(close) handleCloseCameraElements();
    isCameraOpen = false;
    if(close){
        infoContainer?.classList.remove('athena-helper-hide');
    }else{
        infoContainer?.classList.add('athena-helper-hide');
    }

};

const handleCloseCamera = () =>
{
    const { cancelButton } = cameraHelperElementObject();

    document.addEventListener('cameraClosed', disableCamera);
    cancelButton?.removeEventListener('click', disableCamera);
    cancelButton?.addEventListener('click', disableCamera);
};

const handleMobileCameraChoose = async () =>
{
    const {
        cameraSwitchButton,
        leftCameraContainer
    } = cameraHelperElementObject();

    if(!await isDeviceMobileOrTablet()) {
        leftCameraContainer?.classList.add('athena-helper-hide');
        return;
    }

    cameraSwitchButton?.addEventListener('touchend', async () => {
        disableCamera(false);
        await handleOpenCamera(true, cameraFacingMode === 'user' ? 'environment' : 'user');
    });
};

const checkCameraPermission = async () =>
{
    let cameraPermissionGranted = false;

    try {
        if(
            !navigator.permissions ||
            typeof navigator.permissions === 'undefined'
        ) {
            handleCloseCameraElements();
            closeLabelCamera();
        }

        const permissionStatus = await navigator.permissions.query({ name: 'camera' });
        permissionStatus.state === 'granted' ||
        permissionStatus.state === 'prompt' ?
            cameraPermissionGranted = true :
            cameraPermissionGranted = false;

        permissionStatus.onchange = () => {
            if(permissionStatus.state === 'denied') {
                cameraPermissionGranted = false;
                handleCloseCameraElements();
                closeLabelCamera();
            }

            if(permissionStatus.state === 'granted') {
                cameraPermissionGranted = true;
                initializeCamera();
                openLabelCamera();
            }
        };
    } catch (error) {
        cameraPermissionGranted = false;
        throw new Error(`Error checking camera permission: ${error}`);
    }

    return cameraPermissionGranted;
};

const initializeCamera = async () =>
{
    cameraFacingMode = await setInitialCameraView();

    if(!await isIOS() && athenaConfig.cameraCaptureStatus) {
        if(
            await checkIfCameraExists() ||
            await checkCameraPermission()
        ) {
            handleCloseCamera();
            await handleMobileCameraChoose();
            await handleOpenCamera(
                false,
                await setInitialCameraView()
            );
        } else {
            closeLabelCamera();
        }
    } else {
        closeLabelCamera();
    }
};

export default initializeCamera;
