import {handleHtml, hideCategoryMenu} from '../../../global/helpers/athena-global-helper.js';
import { hideAutocompleteBox } from '../../ajax/ajax.js';
import { athenaConfig, athenaConfigOptions } from '../../../global/athena-config.js';
import PerformQuery from '../../../global/indexed-db/indexed-queries.js';
import initializeCamera from './camera-capture.js';
import inputImagePasteUrl from './input-image-paste-url.js';

athenaConfigOptions.cropperInstance = null;
let HeicConverter = null;

/**
 * Handle Global Elements Object
 *
 * @returns {{cropButton: Element, athenaDropZone: Element, containerAfterDrop: Element, containerBeforeDrop: Element, fileInput: Element, cameraButton: Element, previewImage: Element, containerElement: Element}}
 */
function globalElementsObject() {
    return {
        cancelCropButton: document.querySelector('#cancel_crop_button'),
        closeCropButton: document.querySelector('.visual-similarity__close_button'),
        cropButton: document.querySelector('#crop_button'),
        cameraButton: document.querySelector('#visual-similarity__camera-button'),
        containerElement: document.querySelector('#visual_similarity_search'),
        athenaDropZone: document.querySelector('#athena-drop-zone'),
        fileInput: document.querySelector('#file-input'),
        previewImage: document.querySelector('#preview-image'),
        containerBeforeDrop: document.querySelector('.visual-similarity__drop-container'),
        containerAfterDrop: document.querySelector('.visual-similarity__dropped-image-container'),
        visualSimilaritySearchDiv: document.querySelector('.visual-similarity-search'),
        loader: document.querySelector('#visual-similarity__loader'),
        infoContainer: document.querySelector('.visual-similarity-info__container')
    }
}

/**
 * Handler for Elements Append
 */
function handleInitialElementsAppend() {
    //Getting Container Element from Global Object
    const { containerElement } = globalElementsObject();

    containerElement.append(handleHtml(`
        <div class="visual-similarity-search__container">
            <div id="visual-similarity__loader" class="athena-spinner-loader" style="display: none"></div>

            <div class="visual-similarity-p__container">
                <p class="visual-similarity__p">Find Product by Image</p>
            </div>

            <div id="athena-drop-zone" class="visual-similarity__drop-container">
                <div class="visual-similarity__svg-container"></div>
                <div class="visual-similarity__drop-inner-parent-container">
                    <div class="visual-similarity__drop-inner-container">
                        <p class="visual-filter-drag_drop-p">Drag an image here or</p>
                        <div class="visual-similarity__browse-image-container">
                            <label for="file-input" class="visual-similarity-input">
                                <div class="visual-similarity__upload-container"></div>
                                <span>Upload a File</span>
                            </label>

                            <input type="file" id="file-input" accept="image/*" style="display: none;" />
                        </div>
                    </div>

                    <div class="visual-similarity__drop-inner-container">
                        <div>
                            <label for="open-the-camera" class="visual-similarity-input" id="open-the-camera-label">
                                <p class="visual-filter-drag_drop-p">use</p>
                                <div class="visual-similarity__camera-container"></div>
                                <span>Camera</span>
                            </label>
                            <button id="open-the-camera" style="display: none;" type="button"></button>
                        </div>
                    </div>

                    <div class="visual-similarity__drop-inner-container athena-helper-hide" id="visual-similarity__paste-url-search-container">
                        <div class="visual-similarity__paste-url-input-container">
                            <input
                                type="text"
                                id="visual-similarity__input"
                                class="visual-similarity__input"
                            />
                            <div class="visual-similarity__paste-url-paste-icon" id="visual-similarity__paste-url-paste-icon"></div>
                            <div class="visual-similarity__paste-url-x-icon athena-helper-hide" id="visual-similarity__paste-url-x-icon"></div>

                            <div class="visual-similarity__paste-url-error-message athena-helper-hide"></div>
                        </div>

                        <div class="visual-similarity__paste-url-search-container">
                            <label for="visual-similarity__paste-url-search-button" class="visual-similarity__paste-url-search-label">
                                <div></div>
                                <p>Search</p>
                            </label>
                            <button type="button" id="visual-similarity__paste-url-search-button"></button>
                        </div>
                    </div>
                </div>
            </div>

             <div class="visual-similarity-info__container">
                <p>Accepted file types: jpg, jpeg, png, heic, heif, avif & webp</p>
            </div>

            <div class="visual-similarity__dropped-image-container" style="display: none;">
                <div class="visual-similarity__close_button"></div>
                <div class="visual-similarity__inner-image-container">
                    <img id="preview-image" alt="Uploaded Image" src="#" style="display: none;" />
                </div>
                <div class="visual-similarity__button-container">
                    <div style="display: flex;">
                        <button type="button" id="cancel_crop_button" class="cancel-crop-button">Cancel</button>
                        <button type="button" id="crop_button" class="ok-crop-button">Ok</button>
                    </div>
                </div>
            </div>

            <div class="visual-similarity__video-container" style="display: none;">
                <video
                    id="video-element"
                    autoplay
                    playsinline
                >
                </video>

                <div class="visual-similarity__camera-buttons-container">
                    <div class="visual-similarity__camera-button-left">
                        <button
                            id="camera-switch-button"
                            type="button"
                            class="back-camera-select camera-switch-button"
                        >
                            <svg
                                width="40px"
                                height="40px"
                                viewBox="0 0 64 64"
                                xmlns="http://www.w3.org/2000/svg"
                                stroke-width="3"
                                stroke="#000000"
                                fill="none"
                                >
                                <path d="M54.1,51.63H9.9a2,2,0,0,1-2-2V20.37a2,2,0,0,1,2-2h7.54A1,1,0,0,0,18.2,18l4.1-4.95a2,2,0,0,1,1.52-.7H40a2,2,0,0,1,1.51.7L45.6,18a1,1,0,0,0,.76.35H54.1a2,2,0,0,1,2,2V49.63A2,2,0,0,1,54.1,51.63Z"/><path d="M42.5,31.21a10.49,10.49,0,0,1,.29,2.46A10.66,10.66,0,0,1,24.7,41.3" stroke-linecap="round"/><path d="M21.72,35.94A10.65,10.65,0,0,1,39.52,26" stroke-linecap="round"/><polyline points="34.73 27.3 39.66 26.1 39.28 21.48" stroke-linecap="round"/>
                                <polyline points="29.61 40.41 24.44 41.1 24.83 45.73" stroke-linecap="round"/>
                            </svg>
                        </button>
                    </div>
                    <div class="visual-similarity__camera-button-right">
                         <button
                            id="cancel-capture-image"
                            type="button"
                            class="cancel-capture-image cancel-crop-button"
                         >
                            Cancel
                        </button>

                        <button
                            id="capture-image"
                            type="button"
                            class="capture-image ok-crop-button"
                        >
                            Capture
                        </button>
                    </div>
                </div>
            </div>
        </div>
    `, '.visual-similarity-search__container'));
}

/**
 * Store Image to Indexed DB
 *
 * @param getFromConfig
 * @param uploadedImage
 * @param base64
 * @returns {*}
 */
export async function storeImageToIndexedDb(getFromConfig, uploadedImage, base64 = null) {
    let keyImage;
    let image;

    if(getFromConfig && !uploadedImage) {
        image = base64 === null ? athenaConfigOptions.cropper.getCroppedCanvas().toDataURL('image/jpeg') : base64;
        image = image.split(',');
        image = image[1];

        keyImage = image.substring(0, 28).replace(/\//g, '');
        const valueImage = image;

        if((await PerformQuery.get(`${keyImage}`))?.image)
            PerformQuery.delete(`${keyImage}`);

        PerformQuery.store({
            id: keyImage,
            image: valueImage
        });

        if((await PerformQuery.get('original-image-vss'))?.image)
            PerformQuery.delete('original-image-vss');

        const temporaryImageVisual = (await PerformQuery.get('temporary-image-vss'))?.image;

        PerformQuery.store({
            id: 'original-image-vss',
            image: temporaryImageVisual
        });
    } else {
        const originalImage = (await PerformQuery.get('original-image-vss'))?.image;

        if(originalImage) {
            if(
                originalImage.localeCompare(uploadedImage) === 1 ||
                originalImage.localeCompare(uploadedImage) === -1
            )
                return;

            PerformQuery.delete('original-image-vss');
            PerformQuery.store({
                id: `original-image-vss`,
                image: uploadedImage
            });
        } else {
            PerformQuery.store({
                id: `original-image-vss`,
                image: uploadedImage
            });
        }
    }

    return keyImage;
}

/**
 * Handle Crop Button Click Event
 */
function handleCropButtonClick() {
    //Getting Global Elements
    const { cropButton } = globalElementsObject();

    cropButton.addEventListener('click',  async () => {
        const keyImage = await storeImageToIndexedDb(true, null);
        let visualChannel = sessionStorage.getItem('athenaVisualConversionChannel');

        if(visualChannel){
            window.location.href = `${athenaConfig.formUrl}?image=${keyImage}&conversion-channel=visual_${visualChannel}`;
        }else{
            window.location.href = `${athenaConfig.formUrl}?image=${keyImage}&conversion-channel=visual`;
        }

    });
}

/**
 * Handle Camera Click Event Function
 */
function handleCameraClick() {
    //Getting Global Elements
    const { cameraButton, containerElement } = globalElementsObject();
    const backgroundOverlay = document.querySelector('.overlay-background');

    cameraButton.addEventListener('click', () => {
        hideCategoryMenu();
        if(document.body.classList.contains('edit-croper-open')){
            if(document.querySelector('#cancel_crop_button')){
                document.querySelector('#cancel_crop_button').click();
                document.body.classList.remove('edit-croper-open');
                document.body.classList.add('open-visual-box');
                return;
            }
        }
        if(!containerElement?.classList.contains('athena-helper-show')) {

            athenaConfigOptions.voiceRecognition?.disable();

            hideAutocompleteBox();
            containerElement?.classList.add('athena-helper-show');
            backgroundOverlay?.classList.add('background-overlay');
            document.body.classList.add('athena-disable-scroll');
            document.body.classList.add('open-visual-box')

            document.dispatchEvent(athenaConfigOptions.cameraOpenEvent);
        } else {
            containerElement?.classList.remove('athena-helper-show');
            backgroundOverlay?.classList.remove('background-overlay');
            document.body.classList.remove('athena-disable-scroll');
            document.body.classList.remove('open-visual-box')

            document.dispatchEvent(athenaConfigOptions.cameraCloseEvent);
        }
    });
}

/**
 * Set Temporary Visual Image
 *
 * @param result
 */
export async function setTemporaryVisualImage(result) {
    if(result) {
        const tempImage = (await PerformQuery.get('temporary-image-vss'))?.image;
        if(tempImage) PerformQuery.delete('temporary-image-vss');

        PerformQuery.store({
            id: 'temporary-image-vss',
            image: result
        });
    }
}

/**
 * Check image size and throw an error if its more then configurable amount
 *
 * @param imageData
 * @return {boolean}
 */
function checkImageSize(imageData) {

    const MAXIMUM_DATA_ALLOWED_STRING = 'data:,';
    let isImageSizeValid = true;

    const downscaledFileSize = (imageData.length * 0.75 / (1024 * 1024)).toFixed(2);

    if (
        downscaledFileSize > athenaConfigOptions.imageSizeCheckInMb ||
        imageData.includes(MAXIMUM_DATA_ALLOWED_STRING)
    ) {
        isImageSizeValid = false;

        const { athenaDropZone } = globalElementsObject();

        athenaDropZone.append(handleHtml(`
            <h3 class="visual-similarity__file-size-error">
                File is too big, the maximum allowed is ${athenaConfigOptions.imageSizeCheckInMb} Mb.
            </h3>
        `, '.visual-similarity__file-size-error'));
    }

    return isImageSizeValid;
}

/**
 * Downsize Image if Apple Format
 *
 * @param context
 * @param quality
 * @param image
 * @param canvas
 * @return {string}
 */
function downsizeImage(
    context,
    quality,
    image,
    canvas
)
{
    const canvasWidth = 1000;
    const canvasHeight = 1000;

    let width = image.width;
    let height = image.height;

    const aspectRatio = width / height;

    if (aspectRatio > 1) {
        width = canvasWidth;
        height = width / aspectRatio;
        if (height > canvasHeight) {
            height = canvasHeight;
            width = height * aspectRatio;
        }
    } else {
        height = canvasHeight;
        width = height * aspectRatio;
        if (width > canvasWidth) {
            width = canvasWidth;
            height = width / aspectRatio;
        }
    }

    const x = (canvasWidth - width) / 2;
    const y = (canvasHeight - height) / 2;

    canvas.width = canvasWidth;
    canvas.height = canvasHeight;

    context.clearRect(0, 0, canvasWidth, canvasHeight);
    context.drawImage(image, x, y, width, height);

    return canvas.toDataURL('image/jpeg', quality);
}

/**
 * Middleware for downscaling images
 *
 * @param base64Image
 * @param quality
 * @param callback
 */
export function downscaleImageQuality(
    base64Image,
    quality,
    callback
)
{
    const image = new Image();
    image.onload = () => {
        const canvas = document.createElement('canvas');
        const context = canvas.getContext('2d');
        const MAX_SIZE = 1000;

        let imageData;

        if(
            image.width > MAX_SIZE &&
            image.height > MAX_SIZE
        ) {
            imageData = downsizeImage(
                context,
                quality,
                image,
                canvas
            );
        } else {
            canvas.width = image.width;
            canvas.height = image.height;

            context.drawImage(image, 0, 0);
            imageData = canvas.toDataURL('image/jpeg', quality);
        }

        if(checkImageSize(imageData)) {
            callback(imageData);
        }
    };

    image.src = base64Image;
}

/**
 * Function used to display an image with cropper
 *
 * @param response
 * @param image
 * @param containerBeforeDrop
 * @param containerAfterDrop
 */
function displayImage(
    response,
    image,
    containerBeforeDrop,
    containerAfterDrop,
) {
    const fileReader = new FileReader();

    fileReader.onload = () => {
        downscaleImageQuality(
            fileReader.result,
            athenaConfigOptions.imageQuality,
            async (result) => {

                await setTemporaryVisualImage(result);
                await storeImageToIndexedDb(false, result);
                image.src = result;

                containerBeforeDrop?.classList.add('athena-helper-hide');
                containerAfterDrop?.classList.add('athena-helper-show');

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

            });
    };

    fileReader.readAsDataURL(response);
}

/**
 * Handle Upload Image Function
 *
 * @param eventFile
 * @param image
 * @param containerBeforeDrop
 * @param containerAfterDrop
 */
function handleUploadImage(
    eventFile,
    image,
    containerBeforeDrop,
    containerAfterDrop
) {
    sessionStorage.setItem('athenaVisualConversionChannel', 'file_upload');
    const { loader } = globalElementsObject();
    loader ? loader.style.display = 'block' : '';
    const imageTypes = ['image/png', 'image/jpeg', 'image/avif', 'image/webp'];

    if (eventFile) {
        let isAppleFormat =
            eventFile.name?.toLowerCase().includes('heic') ||
            eventFile.name?.toLowerCase().includes('heif');

        if (isAppleFormat) {

            const fileReader = new FileReader();

            fileReader.onload = () => {
                HeicConverter({
                    blob: eventFile,
                    toType: 'image/jpeg'
                })
                    .then(response => {
                        displayImage(
                            response,
                            image,
                            containerBeforeDrop,
                            containerAfterDrop,
                        );

                        if(loader) loader.style.display = 'none';
                    })
                    .catch(error =>  {
                        console.error('Error converting HEIC format to JPEG:', error);
                        if(loader) loader.style.display = 'none';
                    });
            };

            fileReader.readAsArrayBuffer(eventFile);
        } else if (imageTypes.includes(eventFile.type)) {
            displayImage(
                eventFile,
                image,
                containerBeforeDrop,
                containerAfterDrop
            );

            //Removing loader
            setTimeout(() => {
                if(loader) loader.style.display = 'none';
            }, 200);
        } else {
            const { athenaDropZone, infoContainer, fileInput } = globalElementsObject();
            if(infoContainer?.classList.contains('athena-helper-hide'))
                infoContainer?.classList.remove('athena-helper-hide');

            athenaDropZone?.append(handleHtml(`
                <h3 class="visual-similarity__file-type-error">
                    Image file type is not supported.
                </h3>
            `, '.visual-similarity__file-type-error'));

            setTimeout(() => {
                const fileTypeError = athenaDropZone.querySelector('.visual-similarity__file-type-error');
                if(fileTypeError) {
                    fileInput.value = null;
                    fileTypeError.remove();
                }
            }, 2000);

            if(loader) loader.style.display = 'none';
        }
    }
}

/**
 * Handle Drag and Drop Upload Image
 */
function handleDragAndDropUpload() {
    //Getting Global Elements
    let {
        athenaDropZone,
        previewImage,
        containerBeforeDrop,
        containerAfterDrop,
        infoContainer
    } = globalElementsObject();

    // Prevent default behavior for drag-and-drop events
    athenaDropZone.addEventListener('dragover', (event) => {
        event.preventDefault();
        athenaDropZone?.classList.add('visual-similarity__hover');
    });

    athenaDropZone.addEventListener('dragleave', () => {
        athenaDropZone?.classList.remove('visual-similarity__hover');
    });

    //Drop Listener
    athenaDropZone.addEventListener('drop', (event) => {
        event.preventDefault();
        athenaDropZone?.classList.remove('hover');
        document.querySelector('.visual-similarity__file-size-error')?.remove();
        infoContainer?.classList.add('athena-helper-hide');

        event.dataTransfer.getData('text').length > 0 ?
            document.dispatchEvent(new CustomEvent('AthenaDragAndDropTextEvent', {
                detail: {
                    text: event.dataTransfer.getData('text') || ''
                }
            })) :
            handleUploadImage(
                event.dataTransfer.files[0],
                previewImage,
                containerBeforeDrop,
                containerAfterDrop
            );
    });
}

/**
 * Handle On Change Upload
 */
function handleOnChangeUpload() {
    //Getting Global Elements
    const {
        fileInput,
        previewImage,
        containerBeforeDrop,
        containerAfterDrop,
        infoContainer
    } = globalElementsObject();

    fileInput.addEventListener('change', (event) => {
        document.querySelector('.visual-similarity__file-size-error')?.remove();
        infoContainer?.classList.add('athena-helper-hide');

        handleUploadImage(
            event.target.files[0],
            previewImage,
            containerBeforeDrop,
            containerAfterDrop
        );
    });
}

/**
 * Resetting File input on Cancel Function
 */
function resetFileInputOnCancel() {
    const fileInput = document.querySelector('#file-input');
    const fileInputContainer = document.querySelector('.visual-similarity__browse-image-container');

    fileInput?.remove();
    fileInputContainer.append(handleHtml(`<input type="file" id="file-input" accept="image/*" style="display: none" />`, '#file-input'));
    handleOnChangeUpload();
}

/**
 * Reset Cropper Function
 */
function resetCropper() {
    sessionStorage.removeItem('athenaVisualConversionChannel');

    const { containerBeforeDrop, containerAfterDrop, visualSimilaritySearchDiv, infoContainer } = globalElementsObject();

    //Removing Cropper
    if(athenaConfigOptions.cropper) athenaConfigOptions.cropper.destroy();
    //Closing One and Opening another container
    containerAfterDrop?.classList.remove('athena-helper-show');
    containerBeforeDrop?.classList.remove('athena-helper-hide');

    if(visualSimilaritySearchDiv?.classList.contains('visual-similarity-search-active')) {
        visualSimilaritySearchDiv?.classList.remove('visual-similarity-search-active');
    }
    //After Canceling Reset File input and its functionality
    resetFileInputOnCancel();

    if(document.querySelector('.visual-similarity-p__container .visual-similarity__p')){
        document.querySelector('.visual-similarity-p__container .visual-similarity__p').innerHTML = 'Find Product by Image';
    }

    infoContainer?.classList.remove('athena-helper-hide');
}

/**
 * Handle Cancel Crop Button Function
 */
function handleCancelCropButton() {
    //Global Elements
    const {
        cancelCropButton,
        closeCropButton
    } = globalElementsObject();

    cancelCropButton.addEventListener('click', resetCropper);
    closeCropButton.addEventListener('click', resetCropper);
}

/**
 * Initialize libraries
 */
function initializeLibraries() {
    const searchContainer = document.querySelector('.visual-similarity__button-container-search');
    searchContainer.addEventListener('mouseover', () => {
        Promise.all([
            import('../../../global/heic-converter/heic-to-any.js'),
            import('../../../global/cropper/cropper.js')
        ])
            .then(() => {
                setTimeout(() => {
                    athenaConfigOptions.cropperInstance = window.Cropper;
                    HeicConverter = window.HeicConverter;
                }, 500);
            });
    });
}

/**
 * Main Visual Similarity Function
 */
export function visualSimilaritySearch() {
    //Global Elements
    const { cameraButton } = globalElementsObject();

    if(athenaConfig.visualSimilaritySearchStatus) {
        //Initialize Libraries
        initializeLibraries();
        //Append Needed Elements on Start
        handleInitialElementsAppend();
        //Handle Camera Click Event
        handleCameraClick();
        //Handle Drag and Drop Event
        handleDragAndDropUpload();
        //Handle On Change Event
        handleOnChangeUpload();
        //Handle Crop Button Click Event
        handleCropButtonClick();
        //Handle Cancel Button Click Event
        handleCancelCropButton();
        //Init Taking a Picture with Camera
        initializeCamera()
            .then();
        //Init input image paste
        inputImagePasteUrl();
    } else {
        cameraButton?.classList.add('athena-helper-hide');
    }
}
