import { useLocation } from 'react-router-dom';
import { __, sprintf } from '@wordpress/i18n';
import axios from 'axios';
import { showNotification } from '@QPRedux/Slices/notificationSlice/notificationSlice';

export const {
	plugin_root_url,
	nonce,
	ajaxurl,
	menu,
	route_path,
	rest_url,
	admin_url,
	namespace,
	quizpress_nonce,
	user_id,
	_quiz_settings,
	is_plain_permalink,
	addons,
	is_pro,
	certificates,
	certificate_url,
} = window.QuizPressGlobal;

export const isPlainPermalink = Boolean( is_plain_permalink );
export const userId = Boolean( user_id );
export const isPro = Boolean( is_pro );

export const questionSchema = {
	title: '',
	type: '',
	description: '',
	answer_required: false,
	randomize: true,
	display_points: true,
	points: '1.0',
	title: 'Titile tes',
	type: [
		{ value: 'chocolate', label: 'Chocolate' },
		{ value: 'strawberry', label: 'Strawberry' },
		{ value: 'vanilla', label: 'Vanilla' },
	],
	description: '',
	topic: 'CSS',
	sort: [
		{
			label: 'True',
			value: true,
		},
		{
			label: 'False',
			value: false,
		},
	],
};

export const API = axios.create( {
	baseURL: rest_url,
	headers: {
		'content-type': 'application/json',
		'X-WP-Nonce': nonce,
		'Cache-Control': 'no-cache', // Prevent caching
	},
} );

export const useQuery = () => {
	return new URLSearchParams( useLocation().search );
};

export const copyToClipboard = async ( text ) => {
	try {
		await navigator.clipboard.writeText( text );
	} catch ( err ) {
		const tempInput = document.createElement( 'input' );
		tempInput.value = text;
		document.body.appendChild( tempInput );
		tempInput.select();
		document.execCommand( 'copy' );
		document.body.removeChild( tempInput );
	}
};

export const quizModalStyles = {
	overlay: {
		background: 'rgba(35, 40, 45, 0.62)',
	},
	content: {
		top: '50%',
		left: '50%',
		right: 'auto',
		bottom: 'auto',
		marginRight: '-50%',
		transform: 'translate(-50%, -50%)',
	},
};

export const questionModalStyles = {
	overlay: {
		background: 'rgba(35, 40, 45, 0.62)',
	},
	content: {
		top: '50%',
		left: '50%',
		right: 'auto',
		bottom: 'auto',
		marginRight: '-50%',
		transform: 'translate(-50%, -50%)',
	},
};

const makeAxiosError = ( message, response, code = 'UNKNOWN' ) => {
	return new AxiosError(
		message,
		'ERR_' + ( code ? code : 'UNKNOWN' ),
		response.config,
		response.request,
		response
	);
};

const processAjaxError = ( data, response ) => {
	if ( 'string' === typeof data ) {
		throw new Error( data );
	}

	if ( data && 'object' === typeof data && data?.message ) {
		const error = new Error( data.message );
		if ( data?.code ) {
			error.code = data.code;
		}

		throw error;
	}

	if (
		data &&
		Array.isArray( data ) &&
		data.length &&
		data[ 0 ].code &&
		data[ 0 ].message
	) {
		if ( 1 === data.length ) {
			const error = new Error( data[ 0 ].message );
			error.code = data[ 0 ].code;

			throw error;
		}

		throw makeAxiosError(
			__(
				'Something went wrong. Please try again after sometime.',
				'storeengine'
			),
			response
		);
	}

	throw new Error(
		__(
			'Something went wrong. Please try again after sometime.',
			'storeengine'
		)
	);
};

export const makeRequest = async (
	action,
	payload = {},
	isRaw = false,
	suffix = ''
) => {
	let form_data = new FormData(); // eslint-disable-line
	form_data.append( 'action', `quizpress${ suffix }/${ action }` );
	if ( ! payload.security ) {
		form_data.append( 'security', quizpress_nonce );
	}
	Object.entries( payload ).forEach( ( [ key, value ] ) => {
		if ( ! isRaw && typeof value === 'object' && value !== null ) {
			form_data.append( key, JSON.stringify( value ) );
		} else {
			form_data.append( key, value );
		}
	} );
	const response = await axios.post( ajaxurl, form_data );
	const {
		data: { success, data },
	} = response;

	if ( ! success ) {
		processAjaxError( data, response );
	}

	return data;
};

/**
 * Handles errors in Redux Toolkit slices by dispatching an error notification
 * and rejecting the promise with the error message.
 *
 * @param {Object}       thunkAPI - The Redux Toolkit ThunkAPI object containing dispatch and rejectWithValue
 * @param {Error|string} error    - The error object or error message to handle
 * @return {Object} The rejected promise with the error message as value
 *
 * @example
 * try {
 *   // some async operation
 * } catch (error) {
 *   return handleSliceError(thunkAPI, error);
 * }
 */

export const handleSliceError = ( thunkAPI, error ) => {
	// if (error.status === 401 || error.status === 403) {
	// 	thunkAPI.dispatch(
	// 		showNotification({
	// 			message: 'Please login to access to See content',
	// 			isShow: true,
	// 			type: 'info',
	// 		})
	// 	);
	// } else {
	thunkAPI.dispatch(
		showNotification( {
			message:
				error?.response.data.message ??
				error?.response?.message ??
				error?.message,
			isShow: true,
			type: 'error',
		} )
	);
	// }
	return thunkAPI.rejectWithValue( error.message );
};

/**
 * Handles successful operations in Redux Toolkit slices by dispatching a success notification.
 *
 * @param {Object} thunkAPI - The Redux Toolkit ThunkAPI object containing dispatch
 * @param {string} message  - The success message to display
 * @return {void}
 *
 * @example
 * try {
 *   // some async operation
 *   handleSliceSuccess(thunkAPI, "Operation completed successfully");
 * } catch (error) {
 *   // handle error
 * }
 */
export const handleSliceSuccess = ( thunkAPI, message ) => {
	thunkAPI.dispatch(
		showNotification( {
			message: __( message, 'quizpress' ),
			isShow: true,
			type: 'success',
		} )
	);
};

export const generateSlug = ( value ) => {
	return value
		.toLowerCase()
		.replace( /\s+/g, '-' )
		.replace( /[^a-z0-9-]/g, '' );
};

export const capitalizeFirstLetter = ( string = '' ) => {
	if ( string?.includes( '-' ) || string?.includes( '_' ) ) {
		const newString = string.replace( /[-_]/g, ' ' );
		return newString.charAt( 0 ).toUpperCase() + newString.slice( 1 );
	}
	return string.charAt( 0 ).toUpperCase() + string.slice( 1 );
};

export const sliceString = ( text, length = 20, more = '...' ) => {
	if ( ! text || text.length < length ) {
		return text;
	}

	return text.slice( 0, length ).replace( /(^[\s]+|[\s]+$)/g, '' ) + more;
};

export const hideHtmlTags = ( html ) => {
	const div = document.createElement( 'div' );
	div.innerHTML = html;
	return div.textContent || div.innerText || '';
};

export const reactDebounce = ( callback, wait ) => {
	let timeout;
	return ( ...args ) => {
		clearTimeout( timeout );
		timeout = setTimeout( function () {
			callback.apply( this, args );
		}, wait );
	};
};

export const questionTypeOptions = [
	{
		label: __( 'Choice', 'quizpress' ),
		options: [
			{
				label: __( 'Single Choice', 'quizpress' ),
				value: 'single_choice',
			},
			{
				label: __( 'Multiple Choice', 'quizpress' ),
				value: 'multiple_choice',
			},
			{
				label: __( 'Single Choice (Horizontal)', 'quizpress' ),
				value: 'single_choice_horizontal',
			},
			{
				label: __( 'Multiple Choice (Horizontal)', 'quizpress' ),
				value: 'multiple_choice_horizontal',
			},
			{ label: __( 'Drop Down', 'quizpress' ), value: 'drop_down' },
			{ label: __( 'True/False', 'quizpress' ), value: 'true_false' },
			{
				label: __( 'Opt-in (coming soon)', 'quizpress' ),
				value: 'opt_in',
				isDisabled: true,
			},
		],
	},
	{
		label: __( 'Number', 'quizpress' ),
		options: [
			{ label: __( 'Date', 'quizpress' ), value: 'date' },
			{ label: __( 'Number', 'quizpress' ), value: 'number' },
		],
	},
	{
		label: __( 'Text', 'quizpress' ),
		options: [
			{ label: __( 'Short Answer', 'quizpress' ), value: 'short_answer' },
			{ label: __( 'Paragraph', 'quizpress' ), value: 'paragraph' },
		],
	},
	{
		label: __( 'Others', 'quizpress' ),
		options: [
			{
				label: sprintf(
					__( 'Fill In The Blanks %s', 'quizpress' ),
					! isPro ? ' (pro)' : ''
				),
				value: 'fill_in_the_blanks',
				isDisabled: ! isPro,
			},
			{
				label: sprintf(
					__( 'File Upload %s', 'quizpress' ),
					! isPro ? ' (pro)' : ''
				),
				value: 'file_upload',
				isDisabled: ! isPro,
			},
			{
				label: __( 'Text/HTML Section (coming soon)', 'quizpress' ),
				value: 'text_html',
				isDisabled: true,
			},
			{
				label: __( 'Radio Grid (coming soon)', 'quizpress' ),
				value: 'radio_grid',
				isDisabled: true,
			},
			{
				label: __( 'Checkbox Grid (coming soon)', 'quizpress' ),
				value: 'checkbox_grid',
				isDisabled: true,
			},
			{
				label: __( 'Captcha (coming soon)', 'quizpress' ),
				value: 'captcha',
				isDisabled: true,
			},
		],
	},
];

export const runUploader = ( config = {} ) => {
	return new Promise( ( resolve ) => {
		let frame; // eslint-disable-line
		// If the media frame already exists, reopen it.
		if ( frame ) {
			frame.open();
			return;
		}
		// Create a new media frame
		frame = wp.media( {
			title: __( 'Select or Upload Media', 'quizpress' ),
			button: {
				text: __( 'Use this media', 'quizpress' ),
			},
			multiple: false, // Set to true to allow multiple files to be selected
			...config,
		} );

		// When an image is selected in the media frame...
		frame.on( 'select', function () {
			return resolve( frame.state().get( 'selection' ).first().toJSON() );
		} );
		// Finally, open the modal on click
		frame.open();
	} );
};

export const isArray = ( data ) => Array.isArray( data );

export const timeStringGenerator = ( paramTime, unit ) => {
	let timeString = '';
	const time = parseInt( paramTime );
	switch ( unit ) {
		case 'seconds':
			timeString = `00:00:${ time }`;
			break;
		case 'minutes':
			timeString = `00:${ time }:00`;
			break;
		case 'hours':
			timeString = `${ time }:00:00`;
			break;
		case 'days':
			timeString = `${ time * 24 }:00:00`;
			break;
		case 'weeks':
			timeString = `${ time * 168 }:00:00`;
			break;
		default:
			timeString = '00:00:00';
			break;
	}
	return timeString;
};

export const timeToSecondsGenerator = ( paramTime, unit ) => {
	let time = parseInt( paramTime );
	switch ( unit ) {
		case 'seconds':
			time = time;
			break;
		case 'minutes':
			time = time * 60;
			break;
		case 'hours':
			time = time * 3600;
			break;
		case 'days':
			time = time * 86400;
			break;
		case 'weeks':
			time = time * 604800;
			break;
		default:
			time = 0;
			break;
	}
	return time;
};

export const getAddonActiveStatus = ( allAddons, addonName, isPro = false ) => {
	// if pro is inactive
	if ( isPro && ! is_pro ) {
		return false;
	}
	if ( allAddons[ addonName ] ) {
		return allAddons[ addonName ] === true;
	}
	return false;
};

export function formatDateTime( inputDate, formatStr ) {
	const date = new Date( inputDate );
	if ( isNaN( date ) ) {
		return '';
	}

	const pad = ( n, l = 2 ) => String( n ).padStart( l, '0' );

	// Month Names
	const monthsLong = [
		'January',
		'February',
		'March',
		'April',
		'May',
		'June',
		'July',
		'August',
		'September',
		'October',
		'November',
		'December',
	];

	const monthsShort = [
		'Jan',
		'Feb',
		'Mar',
		'Apr',
		'May',
		'Jun',
		'Jul',
		'Aug',
		'Sep',
		'Oct',
		'Nov',
		'Dec',
	];

	// Weekday Names
	const weekdaysLong = [
		'Sunday',
		'Monday',
		'Tuesday',
		'Wednesday',
		'Thursday',
		'Friday',
		'Saturday',
	];

	const weekdaysShort = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];

	const weekdaysMin = [ 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa' ];

	const ordinal = ( n ) => {
		const mod10 = n % 10;
		const mod100 = n % 100;
		if ( mod10 === 1 && mod100 !== 11 ) {
			return n + 'st';
		}
		if ( mod10 === 2 && mod100 !== 12 ) {
			return n + 'nd';
		}
		if ( mod10 === 3 && mod100 !== 13 ) {
			return n + 'rd';
		}
		return n + 'th';
	};

	const timezoneOffset = () => {
		const offset = -date.getTimezoneOffset();
		const sign = offset >= 0 ? '+' : '-';
		const hours = pad( Math.floor( Math.abs( offset ) / 60 ) );
		const minutes = pad( Math.abs( offset ) % 60 );
		return `${ sign }${ hours }:${ minutes }`;
	};

	const timezoneOffsetCompact = () => timezoneOffset().replace( ':', '' );

	const tokens = {
		// YEAR
		YYYY: () => date.getFullYear(),
		YY: () => String( date.getFullYear() ).slice( -2 ),

		// MONTH
		MMMM: () => monthsLong[ date.getMonth() ],
		MMM: () => monthsShort[ date.getMonth() ],
		MM: () => pad( date.getMonth() + 1 ),
		M: () => date.getMonth() + 1,

		// DAY OF MONTH
		DD: () => pad( date.getDate() ),
		D: () => date.getDate(),
		Do: () => ordinal( date.getDate() ),

		// WEEKDAY
		dddd: () => weekdaysLong[ date.getDay() ],
		ddd: () => weekdaysShort[ date.getDay() ],
		dd: () => weekdaysMin[ date.getDay() ],
		d: () => date.getDay(),

		// HOURS
		HH: () => pad( date.getHours() ), // 00–23
		H: () => date.getHours(), // 0–23
		hh: () => pad( date.getHours() % 12 || 12 ),
		h: () => date.getHours() % 12 || 12,

		// MINUTES
		mm: () => pad( date.getMinutes() ),
		m: () => date.getMinutes(),

		// SECONDS
		ss: () => pad( date.getSeconds() ),
		s: () => date.getSeconds(),

		// AM/PM
		A: () => ( date.getHours() >= 12 ? 'PM' : 'AM' ),
		a: () => ( date.getHours() >= 12 ? 'pm' : 'am' ),

		// TIMEZONE
		Z: () => timezoneOffset(), // +06:00
		ZZ: () => timezoneOffsetCompact(), // +0600
	};

	// Collision-safe regex (replace longest tokens first)
	const tokenRegex = new RegExp(
		Object.keys( tokens )
			.sort( ( a, b ) => b.length - a.length )
			.join( '|' ),
		'g'
	);

	return formatStr.replace( tokenRegex, ( match ) => tokens[ match ]() );
}

export const downloadMediaFileById = async ( fileId ) => {
	if ( ! fileId ) {
		return;
	}

	try {
		const response = await fetch( `${ rest_url }wp/v2/media/${ fileId }`, {
			headers: {
				'X-WP-Nonce': nonce,
			},
		} );

		if ( ! response.ok ) {
			throw new Error( 'Failed to fetch media data' );
		}

		const media = await response.json();
		const fileUrl = media?.source_url;

		if ( ! fileUrl ) {
			throw new Error( 'Media URL not found' );
		}

		const link = document.createElement( 'a' );
		link.href = fileUrl;
		link.download = media?.title?.rendered || 'download';
		document.body.appendChild( link );
		link.click();
		document.body.removeChild( link );
	} catch ( error ) {
		console.error( 'Media download failed:', error );
	}
};
