import { FSUploader } from "./SubmissionsClass/FSUploader.js";
import { HashesManager } from "./SubmissionsClass/HashesManager.js";
import { GameSelector } from "./SubmissionsClass/GameSelector.js";
import { MainImageManager } from "./SubmissionsClass/MainImageManager.js";
import { GalleryManager } from "./SubmissionsClass/GalleryManager.js";
import { Credits } from "./SubmissionsClass/Credits.js";

/**
 * If there is some server side errors.
 * We may need reload some things.
 * @type {boolean}
 */
const SERVER_SIDE_ERRORS = document.querySelector('meta[name="submission-has-errors"]')?.content === '1';

/**
 * Object map of errors messages
 * @type {Object<string,string>}
 */
const ERROR_TABLE = {
    isUploading: "A file is uploading. Please wait.",
    noFiles: "Please select a file to upload",
    uploadError: "One or more files failed to upload.",
    notAllFilesDone: "Not all the files have finished uploading yet.",
    noModifications: "Please select at least a type of hack.",
    noSystems: "Please select at least a system.",
    noDescription: "Please provide a description.",
    noGame: "Please provide a game or create a new one and fill all the required fields.",
    noLanguages: "Please select at least a language.",
    noAuthors: "Please provide at least an author or create a new one and fill all the required fields.",
    noMainImage: "Please upload a main image.",
    noGalleryImages: "Please select at least a gallery image.",
    isSubmitting: "The entry is already during submission."
}

/**
 * Current section.
 * @returns {string}
 * @constructor
 */
const SECTION = () => document.querySelector("meta[name='fs-section']")?.content ?? '';
const CSRF = () => document.querySelector("meta[name='csrf-token']")?.content ?? '';

window.FSUploader = FSUploader;
window.HashesManager = HashesManager;
window.GameSelector = GameSelector;
window.MainImageManager = MainImageManager;
window.GalleryManager = GalleryManager;
window.Credits = Credits;

/**
 * Verify if at least one checkbox is checked in this element.
 * @param {HTMLElement} element
 * @returns {boolean}
 */
function verifyCheckboxes( element ){
    if( !parent ) return false;
    return Array.from(element.querySelectorAll('input[type="checkbox"]')).some(el => el.checked);
}

/**
 * Verify if an EasyMDE field is filled.
 *
 * @param {string} fieldName
 * @returns {boolean}
 */
function verifyMDE( fieldName ){
    const textarea = document.querySelector('#field_' + fieldName);
    if( textarea && textarea.value.trim().length > 0 ) {
        return true;
    }

    const field = window['mde_' + fieldName] || null;
    return field && typeof field.value === 'function' && field.value().trim().length > 0;
}

window.SubmissionVerifications = {

    /**
     * Verify if we are in an upload.
     * @param {FSUploader} Uploader
     * @returns {boolean}
     */
    step1_DuringFSUpload: function( Uploader ){
        return !Uploader.isUploading;
    },

    /**
     * Verify if at least one file is uploaded.
     * @param {FSUploader} Uploader
     * @returns {boolean}
     */
    step2_NoFilesFSUpload: function( Uploader ){
        return Uploader.numberOfFiles > 0;
    },

    /**
     * Verify if any files haven't error.
     * @param {FSUploader} Uploader
     * @returns {boolean}
     */
    step3_ErrorsFSUpload: function( Uploader ){
        return !Uploader.hasErrors;
    },

    /**
     * Check if all files are uploaded.
     * @param {FSUploader} Uploader
     * @returns {boolean}
     */
    step4_AllFilesUploadedFSUpload: function( Uploader ){
        return Uploader.allFilesUploaded;
    },

    /**
     * Verify if at least one checkbox of romhacks modifications is checked.
     * @returns {boolean}
     */
    step5_RomhacksModificationsCheckboxes: function(){
        return verifyCheckboxes( document.querySelector( '#modifications-group' ) );
    },

    step5_UtilitiesSystemsCheckboxes: function(){
        return verifyCheckboxes( document.querySelector( '#systems-group' ) );
    },

    /**
     * Verify if the description field has at least one character.
     * @returns {boolean}
     */
    step6_VerifyDescription: function(){
        return verifyMDE('description');
    },

    /**
     * Verify if a game is provided.
     * @param element this.$el
     * @returns {boolean}
     */
    step7_VerifyGame: function( element ){

        const GAME_SELECTOR_MODE = document.querySelector('input[name="game_selection_mode"]')?.value ?? "game";
        if( GAME_SELECTOR_MODE === 'platform' || GAME_SELECTOR_MODE === 'none' )
            return true;

        // Check if we have an already existent selected game.
        const GAME_ID_INPUT = document.querySelector('input[name="game_id"]');
        if( GAME_ID_INPUT ){
            if( GAME_ID_INPUT.value !== '' && Number(GAME_ID_INPUT.value) > 0){
                return true;
            }
        }

        // Check if we have a new game.
        let gameSelector = element.querySelector('[x-data="GameSelector()"]');
        gameSelector = gameSelector ? Alpine.$data(gameSelector) : null;
        if( gameSelector !== null ){

            if( !gameSelector.name || !gameSelector.name.toString().trim().length )
                return false;
            if( !gameSelector.platformId || gameSelector.platformId === '' || gameSelector.platformId === 0 )
                return false;
            if( !gameSelector.genreId || gameSelector.genreId === '' || gameSelector.genreId === 0 )
                return false;

            return true;
        }

        return false;
    },

    /**
     * Verify if at least one checkbox of languages is checked.
     * @returns {boolean}
     */
    step8_LanguagesCheckboxes: function(){
        return verifyCheckboxes( document.querySelector( '#languages-group' ) );
    },

    /**
     * Verify if at least one (new) author has been filled.
     * @return {boolean}
     */
    step9_verifyAuthors: function(){
        const authorField = document.querySelectorAll('input[name="authors[]"]');
        const newAuthorField = document.querySelectorAll('input[name="new-authors[]"]');

        return ( authorField.length > 0 || newAuthorField.length > 0 );
    },

    /**
     * Verify if a main image has been uploaded.
     * @param element this.$el
     * @return {boolean}
     */
    step10_verifyMainImage: function( element ){
        let MainImageData = element.querySelector('[x-data="MainImageManager()"]');
        MainImageData = MainImageData ? Alpine.$data(MainImageData) : null;

        if( ! MainImageData ){
            return false;
        }

        return MainImageData.uploaded;
    },

    /**
     * Verify if at least one image is uploaded in the gallery.
     * @param element this.$el
     * @return {boolean}
     */
    step11_verifyGallery: function( element){
        let GalleryData = element.querySelector('[x-data="GalleryManager()"]');
        GalleryData = GalleryData ? Alpine.$data(GalleryData) : null;

        if( ! GalleryData ){
            return false;
        }

        return GalleryData.number > 0 && GalleryData.allUploaded;
    }

}

/**
 * Handle entire submission process.
 */
window.Submission = function(){
    return {

        /**
         * If the script is during a try of submission process.
         * @type {boolean}
         */
        duringSubmissionProcess: false,

        /**
         * Error checked.
         * @type {string|null}
         */
        errorKey: null,

        /**
         * Return error message.
         * @return {string}
         */
        get errorMessage(){
          return ERROR_TABLE[this.errorKey] ?? "Unknown error";
        },

        init(){
        },

        /**
         * Get current FSUploader if initialized.
         *
         * @returns {FSUploader|null}
         * @constructor
         */
        get Uploader(){
            const el = this.$el.querySelector('[x-data="FSUploader()"]');
            return el ? Alpine.$data(el) : null;
        },

        /**
         * Do each form verifications.
         * Update also this.errorKey.
         *
         * @returns {boolean}
         */
        verifyForm(){

            console.info( "Step 1: During File upload" );
            if( !SubmissionVerifications.step1_DuringFSUpload( this.Uploader ) ){
                this.errorKey = "isUploading";
                return false;
            }

            console.info( "Step 2: No files uploaded" );
            if( !SubmissionVerifications.step2_NoFilesFSUpload( this.Uploader ) ){
                this.errorKey = "noFiles";
                return false;
            }

            console.info( 'Step 3: Error in file upload')
            if( !SubmissionVerifications.step3_ErrorsFSUpload( this.Uploader ) ){
                this.errorKey = "uploadError";
                return false;
            }

            console.info("Step 4: All files uploaded");
            if( !SubmissionVerifications.step4_AllFilesUploadedFSUpload( this.Uploader ) ){
                this.errorKey = "notAllFilesDone";
                return false;
            }

            if( SECTION() === "romhacks" || SECTION() === "lua-scripts" ){
                console.info( "Step 5: Verify modifications")
                if( !SubmissionVerifications.step5_RomhacksModificationsCheckboxes()){
                    this.errorKey = "noModifications";
                    return false;
                }
            } else if( SECTION() === "utilities" ){
                console.info( "Step 5: Verify systems");
                if( !SubmissionVerifications.step5_UtilitiesSystemsCheckboxes()){
                    this.errorKey = "noSystems";
                    return false;
                }
            }

            console.info( "Step 6: Verify description");
            if( !SubmissionVerifications.step6_VerifyDescription() ){
                this.errorKey = "noDescription";
                return false;
            }

            console.info( "Step 7: Verify game");
            if( !SubmissionVerifications.step7_VerifyGame( this.$el ) ){
                this.errorKey = "noGame";
                return false;
            }

            console.info("Step 8: Verify languages");
            if( !SubmissionVerifications.step8_LanguagesCheckboxes()){
                this.errorKey = "noLanguages";
                return false;
            }

            console.info( "Step 9: Verify authors" );
            if( !SubmissionVerifications.step9_verifyAuthors()){
                this.errorKey = "noAuthors";
                return false;
            }

            console.info( "Step 10: Verify Main image" );
            if( !SubmissionVerifications.step10_verifyMainImage( this.$el )){
                this.errorKey = "noMainImage";
                return false;
            }

            console.info( "Step 11: Verify gallery images" );
            if( !SubmissionVerifications.step11_verifyGallery( this.$el )){
                this.errorKey = "noGalleryImages";
                return false;
            }

            return true;

        },

        /**
         * Scroll to the specific error field.
         */
        scrollToError(){
            const refMap = {
                noFiles: 'uploadTarget',
                isUploading: 'uploadTarget',
                notAllFilesDone: 'uploadTarget',
                uploadError: 'uploadTarget',
                noModifications: 'modificationsGroup',
                noSystems: 'systemsGroup',
                noDescription: 'descriptionField',
                noGame: 'gameSelector',
                noLanguages: 'languagesGroup',
                noAuthors: 'authorsSelector',
                noMainImage: 'main-image-field',
                noGalleryImages: 'gallery-field',
                isSubmitting: 'submitButton'
            };

            const targetKey = refMap[this.errorKey];

            const target = this.$refs[targetKey]
                    || this.$el.querySelector(`[data-target="${targetKey}"]`)
                    || this.$el.querySelector(`[x-ref="${targetKey}"]`)
                    || this.$el.querySelector('.upload-list')
                    || this.$el.querySelector('.form-upload');

            if (target) {
                target.scrollIntoView({behavior: 'smooth', block: 'center'});
                return;
            }
        },

        /**
         * If you want to submit the form.
         * @param {Event} e
         */
        submitForm( e ){

            if( this.duringSubmissionProcess )
                return; // Don't submit two times.

            this.errorKey = null; // Reset.
            this.duringSubmissionProcess = true;

            const STATE = document.querySelector('select[name="submit-state"]')?.value;
            if( STATE === 'draft' ){
                e.target.submit();
                return;
            }

            if( !this.verifyForm() ){

                this.scrollToError();

                this.duringSubmissionProcess = false;
                return;
            }

            e.target.submit();
        },

        async requestFeatured( entryId ){
            const csrf = CSRF();

            const response = await fetch(`/api/entry/${entryId}/featured`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRF-Token': csrf
                }
            });
            const json = await response.json();

            const entry_featured_button = document.querySelector('#entry-featured-button');
            const entry_featured_body = document.querySelector('#entry-featured-body');

            if( json.success ){
                entry_featured_body.innerHTML = '<p>Request submitted</p>';
                entry_featured_button.style.display = 'none';
            } else {
                entry_featured_body.innerHTML = '<p>Request failed. Please refresh the page and retry.</p>';
                entry_featured_button.style.display = 'none';
            }

        }

    }
}
