import './settings.scss';
import { debounce, aspectRatio } from './helpers';
import { store, getContext, getConfig } from '@wordpress/interactivity';
const domParser = new DOMParser();
const d = document;
const qs = d.querySelector.bind( d ) as typeof document.querySelector;
const dialog = qs< HTMLDialogElement >( 'dialog[data-wp-interactive="nextgenthemes_arve_dialog"]' );

setupInteractivityApi();
setBodyBackgroundColorAsCssVar();

function setBodyBackgroundColorAsCssVar() {
	const backgroundColor = window.getComputedStyle( d.body ).backgroundColor;
	const wrap = qs( '.wrap--nextgenthemes' );

	if ( wrap ) {
		wrap.setAttribute( 'style', `--ngt-wp-body-bg: ${ backgroundColor };` );
	}
}

// ACF
window.jQuery( document ).on( 'click', '.arve-btn:not([data-editor="content"])', ( e: Event ) => {
	e.preventDefault();

	const openBtn = qs< HTMLButtonElement >(
		'[data-wp-on--click="actions.openShortcodeDialog"][data-editor="content"]'
	);
	const insertBtn = qs< HTMLButtonElement >( '[data-wp-on--click="actions.insertShortcode"]' );

	if ( ! openBtn || ! insertBtn || ! dialog ) {
		console.error( 'Open btn, insert btn or dialog not found' ); // eslint-disable-line
		return;
	}

	openBtn.dispatchEvent( new Event( 'click' ) );
} );

function setupInteractivityApi() {
	const namespace = qs< HTMLElement >( '[data-wp-interactive^="nextgenthemes"]' )?.dataset
		?.wpInteractive;

	if ( ! namespace ) {
		// In ARVE this script will always be loaded but the config is only output when the media button is on the page
		return;
	}
	const config = getConfig( namespace ) as configInterface;

	// eslint-disable-next-line @typescript-eslint/no-unused-vars
	const { state, actions, callbacks, helpers } = store( namespace, {
		state: {
			isValidLicenseKey: () => {
				const context = getContext< optionContext >();
				return 'valid' === state.options[ context.option_key + '_status' ];
			},
			is32charactersLong: () => {
				const context = getContext< optionContext >();
				return state.options[ context.option_key ].length === 32;
			},
			get isActiveTab() {
				const context = getContext< optionContext >();

				if ( ! context.activeTabs ) {
					return true; // shortcode dialog has no sections
				}

				return true === context?.activeTabs[ context.tab ];
			},
		},
		actions: {
			toggleHelp: () => {
				state.help = ! state.help;
			},
			openShortcodeDialog: ( event: Event ) => {
				const editorId = event.target instanceof HTMLElement && event.target.dataset.editor;

				if ( ! dialog || ! editorId ) {
					console.error( 'Dialog or editorId not found' ); // eslint-disable-line
					return;
				}

				dialog.dataset.editor = editorId;
				dialog.showModal();
			},
			insertShortcode: () => {
				const editorId = dialog?.dataset.editor;

				if ( ! editorId ) {
					console.error( 'Editor ID not found' ); // eslint-disable-line
				} else if ( 'content' === editorId ) {
					window.wp.media.editor.insert( state.shortcode );
				} else {
					// Ensure TinyMCE is loaded and the editor exists
					if (
						typeof window.tinymce === 'undefined' ||
						! window.tinymce.get( editorId )
					) {
						console.error( 'TinyMCE not initialized for field: ' + editorId ); // eslint-disable-line
						return;
					}

					window.tinymce.get( editorId ).insertContent( state.shortcode );
				}

				actions.closeShortcodeDialog();
			},
			closeShortcodeDialog: () => {
				if ( dialog ) {
					dialog.close();
				}
			},
			changeTab: () => {
				const context = getContext< optionContext >();

				for ( const key in context.activeTabs ) {
					context.activeTabs[ key ] = false;
				}
				context.activeTabs[ context.tab ] = true;
			},
			inputChange: ( event: Event ) => {
				const context = getContext< optionContext >();

				const isInput = event?.target instanceof HTMLInputElement;
				const isSelect = event?.target instanceof HTMLSelectElement;

				if ( ! isInput && ! isSelect ) {
					throw new Error( 'event.target is not HTMLInputElement or HTMLSelectElement' );
				}

				if ( 'arveUrl' in event.target.dataset ) {
					helpers.extractFromEmbedCode( event.target.value );
				} else {
					state.options[ context.option_key ] = event.target.value;
				}

				actions.saveOptions();
			},
			checkboxChange: ( event: Event ) => {
				const context = getContext< optionContext >();

				const isCheckbox =
					event?.target instanceof HTMLInputElement && 'checkbox' === event?.target?.type;

				if ( ! isCheckbox ) {
					throw new Error( 'event.target is not HTMLInputElement type=checkbox' );
				}

				state.options[ context.option_key ] = event?.target.checked;

				actions.saveOptions();
			},
			selectImage: () => {
				if ( dialog ) {
					dialog.close();
				}

				const context = getContext< optionContext >();
				const image = window.wp
					.media( {
						title: 'Upload Image',
						multiple: false,
					} )
					.open()
					.on( 'select', function () {
						// This will return the selected image from the Media Uploader, the result is an object
						const uploadedImage = image.state().get( 'selection' ).first();
						// We convert uploadedImage to a JSON object to make accessing it easier
						const attachmentID = uploadedImage.toJSON().id;
						state.options[ context.option_key ] = attachmentID;
						if ( dialog ) {
							dialog.showModal();
						}
					} )
					.on( 'close', function () {
						if ( dialog ) {
							dialog.showModal();
						}
					} );
			},
			deleteCaches: () => {
				const context = getContext< clearCacheContext >();

				actions.restCall( config.restUrl + '/delete-caches', {
					type: context.type,
					prefix: context.prefix,
					like: context.like,
					not_like: context.type,
					delete_option: context.delete_option,
				} );
			},
			// debounced version created later
			saveOptionsReal: () => {
				actions.restCall( config.restSettingsUrl, {
					[ namespace ]: state.options,
				} );
			},
			restCall: (
				restUrl: string,
				body: Record< string, any >,
				refreshAfter: boolean = false
			) => {
				if ( state.isSaving ) {
					state.message = 'trying to save too fast';
					return;
				}

				// set the state so that another save cannot happen while processing
				state.isSaving = true;
				state.message = 'Saving…';

				let hadError = false;

				// Make a POST request to the REST API route that we registered in our PHP file
				fetch( restUrl, {
					method: 'POST',
					body: JSON.stringify( body ),
					headers: {
						'Content-Type': 'application/json',
						'X-WP-Nonce': config.nonce,
					},
				} )
					.then( ( response ) => {
						if ( ! response.ok ) {
							hadError = true;
						}
						return response.json();
					} )
					.then( ( json ) => {
						if ( hadError ) {
							state.message = 'Error:';
							state.debug = JSON.stringify( json, null, 2 );
						}

						if ( ! hadError ) {
							setTimeout( () => ( state.message = '' ), 666 );
						}
					} )
					.catch( ( error ) => {
						state.message = error.message;
					} )
					.finally( () => {
						state.isSaving = false;

						if ( refreshAfter ) {
							window.location.reload();
						}
					} );
			},
			eddLicenseAction() {
				const context = getContext< optionContext >();

				actions.restCall(
					config.restUrl + '/edd-license-action',
					{
						option_key: context.option_key,
						edd_store_url: context.edd_store_url, // EDD Store URL
						edd_action: context.edd_action, // edd api arg has same edd_ prefix
						item_id: context.edd_item_id, // edd api arg WITHOUT edd_ prefix
						license: state.options[ context.option_key ], // edd api arg WITHOUT edd_ prefix
					},
					true
				);
			},
			resetOptionsSection() {
				const context = getContext< optionContext >();
				const sectionToReset = context.tab;

				Object.entries( config.defaultOptions ).forEach( ( [ section, options ] ) => {
					if ( 'all' === sectionToReset ) {
						// reset all
						Object.entries( options ).forEach( ( [ key, value ] ) => {
							state.options[ key ] = value;
						} );
					} else {
						Object.entries( options ).forEach( ( [ key, value ] ) => {
							if ( section === sectionToReset ) {
								state.options[ key ] = value;
							}
						} );
					}
				} );

				actions.saveOptionsReal();
			},
		},
		callbacks: {
			updateShortcode() {
				let out = '';

				for ( const [ key, value ] of Object.entries( state.options ) ) {
					if ( 'credentialless' === key ) {
						if ( false === value ) {
							out += `${ key }="false" `;
						}
					} else if ( true === value ) {
						out += `${ key }="true" `;
					} else if ( value ) {
						out += `${ key }="${ value }" `;
					}
				}

				state.shortcode = '[arve ' + out + '/]';
			},
			// updatePreview() {
			// 	const url = new URL( 'https://symbiosistheme.test/wp-json/arve/v1/shortcode' );
			// 	const params = new URLSearchParams();
			// 	const options = getContext< optionContext >().options;
			// 	const preview = document.getElementById( 'preview' );

			// 	if ( ! preview ) {
			// 		throw new Error( 'No preview element' );
			// 	}

			// 	for ( const [ key, value ] of Object.entries( options ) ) {
			// 		if ( true === value ) {
			// 			params.append( key, 'true' );
			// 		} else if ( value.length ) {
			// 			params.append( key, value );
			// 		}
			// 	}

			// 	url.search = params.toString();

			// 	fetch( url.href )
			// 		.then( ( response ) => response.json() )
			// 		.then( ( data ) => {
			// 			preview.innerHTML = data.html;
			// 		} )
			// 		.catch( () => {
			// 			//console.error( error );
			// 		} );
			// },
		},
		helpers: {
			debugJson: ( data: Record< string, unknown > ) => {
				state.debug = JSON.stringify( data, null, 2 );
			},
			extractFromEmbedCode: ( url: string ) => {
				const iframe = domParser
					.parseFromString( url, 'text/html' )
					.querySelector( 'iframe' );
				const srcAttr = iframe && iframe.getAttribute( 'src' );

				if ( srcAttr ) {
					url = srcAttr;

					if ( iframe.width && iframe.height ) {
						const ratio = aspectRatio( iframe.width, iframe.height );

						if ( '16:9' !== ratio ) {
							state.options.aspect_ratio = ratio;
						}
					}
				}
				state.options.url = url;
			},
		},
	} ) as any;

	actions.saveOptions = debounce( actions.saveOptionsReal, 1111 );

	if ( 'nextgenthemes_arve_dialog' === namespace ) {
		actions.saveOptions = () => {};
	}
}

declare global {
	interface Window {
		wp: {
			media: wpMedia;
		};
		jQuery: any;
		tinymce: {
			get: ( id: string ) => any;
		};
	}
}

interface wpMedia {
	( options: any ): any; // Function-like usage
	open: () => this; // Method to initialize the media dialog
	on: ( eventName: string, callback: ( data: any ) => void ) => this; // Event subscription
	editor: {
		insert: ( content: string ) => void; // Method to insert content into the editor}
	};
}

interface optionContext {
	tab: string;
	option_key: string;
	edd_item_id: string;
	edd_action: string;
	edd_store_url: string;
	activeTabs: { [ key: string ]: boolean };
}

interface clearCacheContext {
	type: string;
	like: string;
	not_like: string;
	prefix: string;
	delete_option: string;
}

interface configInterface {
	restUrl: string;
	restSettingsUrl: string;
	nonce: string;
	defaultOptions: Record< string, string | number | boolean >;
}
