/**
 * @typedef {Object} ProductDetails
 * @property {string} entry_id - The product entry_id, e.g. "2003"
 * @property {string} sku - The product SKU, e.g. "PP906"
 * @property {string} name - The product name, e.g. "PicoScope 2204A"
 * @property {string} model - The product model, e.g. "2204A"
 * @property {string} price - The product price, e.g. "<sup class='cursym'>£</sup>99.99",
 * @property {string} price_value - The product price value, e.g. "99.99"
 * @property {string} channels - The product channels, e.g. "2"
 * @property {string} bandwidth - The product bandwidth, e.g. "10 MHz"
 * @property {string} bandwidth_unit - The product bandwidth unit, e.g. "MHz"
 * @property {string} buffer - The product buffer, e.g. "8"
 * @property {string} buffer_unit - The product buffer unit, e.g. "MS"
 * @property {string?} mso - The product MSO, e.g. "tick"
 * @property {string?} stock - The product stock, e.g. "239"
 * @property {string?} image - The products 3D image, e.g. "3d/2204A.png"
 */
/**
 * @typedef {Object} ProductStock
 * @property {string} entid - The product entid, e.g. "2003"
 * @property {string} stock - The product stock, e.g. "239"
 */
/**
 * @typedef {Object} Option
 * @property {[keyof State]} [key] - The options key, e.g. "bandwidth"
 * @property {boolean} [disabled] - The options disabled, e.g. false
 */
/**
 * @typedef {Object} ConfigurationOption
 * @property {string} [name] - The configuration name, e.g. "channels"
 * @property {string} [label] - The configuration label, e.g. "Channels"
 * @property {string} [type] - The configuration type, e.g. "radio"
 * @property {string?} [class] - The configuration class, e.g. "PWthird"
 * @property {Option[]} [option] - The configuration options, e.g. [{label: "2", disabled: false}, {label: "4", disabled: true}]
 */
/**
 * @typedef {Object} ProductImage
 * @property {string} [path] - The product image path, e.g. "https://www.picotech.com/images/3d/2204A.png"
 * @property {string[]} [entry_ids] - The product image entry_ids, e.g. ["2003", "2004"]
 */

/**
 * @typedef {Object} State
 * @property {string} [bandwidth] - The state bandwidth, e.g. "10 MHz"
 * @property {string} [channels] - The state channels, e.g. "2"
 * @property {boolean} [MSO] - The state MSO, e.g. true
 */

/** @type {unknown} */
let jsonFile;
/** @type {unknown} */
let jsonStockFile;
/** @type {ProductDetails[]} */
let products;
/** @type {ConfigurationOption[]} */
let configurationOptions;
/** @type {string[]} */
const viewedProducts = [];
/** @type {ProductImage[]} */
const productImages = [
	{
		path: "3200D/PS320xD_##.jpg",
		entry_ids: ["8651", "8691", "8701", "8711"],
	},
	{
		path: "3400D/PS340xD_##.jpg",
		entry_ids: ["8671", "8721", "8731", "8741"],
	},
	{
		path: "3200DMSO/PS320xDMSO_##.jpg",
		entry_ids: ["8661", "6881", "6831", "6841"],
	},
	{
		path: "3400DMSO/PS340xDMSO_##.jpg",
		entry_ids: ["8681", "6851", "6861", "6871"],
	},
];

/**
 * @description Function that returns the query string value of a given key from the URL
 *
 * @param {string} key - The query string key to get the value of
 * @returns {string | undefined} - The query string value of the given key
 */
const getQueryStringValue = (key) => {
	return decodeURIComponent(
		window.location.search.replace(new RegExp(`^(?:.*[&\\?]${encodeURIComponent(key).replace(/[\.\+\*]/g, "\\$&")}(?:\\=([^&]*))?)?.*$`, "i"), "$1")
	);
};

/**
 * @description Function to returns the radio configuration options HTML
 *
 * @param {ConfigurationOption['name']} name - The configuration option name
 * @param {Option[]} options - The configuration options to build the HTML from
 * @param {string | number} value - The configuration option value
 * @returns {string | void}
 */
const buildRadioConfigurationOptions = (name, options, value) => {
	if (!options?.length) throw new Error("No configuration option found");

	return `
		<div class="pico-configurator_radio">
			${options
				.map(
					(option) => `
				<label for="radio-option-${option.key}" class="configuration-button-${name}${option.key === value ? " active" : ""}"${option.disabled ? " disabled" : ""}>
					<input type="radio" name="radio-option-${name}" id="radio-option-${option.key}" value="${option.key}"${option.key === value ? " checked" : ""}${
						option.disabled ? " disabled" : ""
					}>
					<span>${option.key}</span>
				</label>
			`
				)
				.join("")}
		</div>
	`;
};

/**
 * @description Function to returns the checkbox configuration options HTML
 *
 * @param {ConfigurationOption['name']} name - The configuration option name
 * @param {string} label - The checkbox label
 * @param {boolean} value - The configuration option value
 * @returns {string | void}
 */
const buildCheckboxConfigurationOptions = (name, label, value) => {
	if (!label) throw new Error("No configuration option found");

	return `
		<div class="pico-configurator_radio">
			<label for="checkbox-option-${name}" class="configuration-button-${name}${value ? " active" : ""}">
				<input type="radio" name="checkbox-option-${name}" id="checkbox-option-${name}" value="${label}"${value ? " checked" : ""}>
				<span>${label}</span>
			</label>
		</div>
	`;
};

/**
 * @description Function to returns the product configuration options HTML
 *
 * @param {ConfigurationOption} option - The configuration option to build the HTML from
 * @param {string | number | boolean | undefined} value - The configuration option value
 * @returns {string | void}
 */
const buildConfigurationOptions = (option, value) => {
	if (!option?.type) throw new Error("No configuration option found");
	/** @type {string} */

	/** @description Switch between the configuration option types */
	switch (option.type) {
		case "radio":
			return buildRadioConfigurationOptions(option.name, option.options, value) ?? "";
		case "checkbox":
			return buildCheckboxConfigurationOptions(option.name, option.label || option.name, value ?? false) ?? "";
		default:
			return ``;
	}
};

/**
 * @description Function to returns the product information HTML
 *
 * @param {ProductDetails} product - The product details to build the HTML from
 * @returns {string | void}
 */
const buildProductInformation = (product) => {
	if (!product?.sku) throw new Error("buildProductInformation: No product found");

	return `
		<div>
			<p class="pico-configurator_label">Memory</p>
			<p class="pico-configurator_value">${product.buffer} ${product.buffer_unit}</p>
		</div>
		<div>
			<p class="pico-configurator_label">Model</p>
			<p class="pico-configurator_value">${product.model}</p>
		</div>
		<div>
			<p class="pico-configurator_label">Price</p>
			<p class="pico-configurator_value price">${product.price}</p>
		</div>
	`;
};

/**
 * @description Function to returns the price & stock HTML
 *
 * @param {ProductDetails} product - The product details to build the HTML from
 * @returns {string | void}
 */
const buildPriceAndStock = (product) => {
	if (!product?.sku) throw new Error("buildPriceAndStock: No product found");

	console.log("BUILD PRICE AND STOCK", product);

	return `
		<div class="pico-grid_span_2">
			<div class="pico-stock_message ${
				product.stock >= 6 ? "pico-stock_message--in-stock" : product.stock >= 2 ? "pico-stock_message--low-stock" : "pico-stock_message--out-of-stock"
			}" data-stock="${product.stock >= 6 ? "In stock" : product.stock >= 2 ? "Low stock" : "Out of stock"}">
				<i class="fa-regular ${product.stock >= 6 ? "fa-check-circle" : product.stock >= 2 ? "fa-exclamation-circle" : "fa-info-circle rem"}"></i>
				${
					product.stock >= 6
						? "In stock. Available for despatch."
						: product.stock >= 2
						? $.cookie("exp__geomodal") === "US"
							? "Call for anticipated lead times +1-800-591-2796"
							: "Low Stock. Order now."
						: $.cookie("exp__geomodal") === "US"
						? "Call for anticipated lead times +1-800-591-2796"
						: "Available for back order. More stock coming soon."
				}
			</div>
			${ $.cookie("exp__geomodal") === "US" ? `<span class="shipalert"><p style="font-size:14px;"><img style="width:2rem; height:2rem" src="/images/usa-flag-round-circle-icon.svg" /> Shipped from Texas</p></span>`:""}
			<input type="hidden" id="item_qty" name="item_qty" value="1" />
			<button type="submit" alt="add to cart" name="submit">Add to cart <i class="fa-light fa-cart-plus"></i></button>
		</div>
	`;
};

/**
 * @description Function to renders the product image
 *
 * @param {ProductDetails['image']} image - The product image to render
 * @returns {void}
 */
const renderProductImage = (image) => {
	if (!image?.length) return;
	$("#image360").reel("images", `/images/uploads/threesixty/${image}`);
};

/**
 * @description Function to add the data layer click event to the submit button
 *
 * @param {ProductDetails} product - The product details to build the HTML from
 * @returns {void}
 */
const addDataLayerClickEvent = (product) => {
	if (!product?.sku) throw new Error("addDataLayerClickEvent: No product found");

	// add the onclick attr to the button with the type of submit
	$("button[type=submit]").attr(
		"onclick",
		`dataLayer.push({'event': 'add_to_cart', 'ecommerce': {'currency': '${$.cookie("exp__currency")}', 'value': '${parseFloat(product.price_value).toFixed(
			2
		)}', 'items': [{'item_id': '${product.sku}', 'item_url': '${$(location).attr("href")}', 'item_name': '${product.name}', 'price': '${parseFloat(
			product.price_value
		).toFixed(2)}', 'quantity': '1'}]}});`
	);
};

/**
 * @description Function to render the share button HTML
 *
 * @param {ProductDetails} product - The product details to build the HTML from
 * @returns {Promise<void>}
 */
const renderShareButton = async (product) => {
	if ($(".pico-share_button").length) {
		await $(".pico-share_button").remove();
	}
	await $("#image360-reel").append(`<div class="pico-share_button"><i class="fa-light fa-share-alt"></i></div>`);
	$(".pico-share_button").on("click", function () {
		const el = document.createElement("textarea");
		const currentUrl = window.location.href?.split("?")[0];
		el.value = `${currentUrl}?kit=${product.model}&utm_source=sharebutton`;
		document.body.appendChild(el);
		el.select();
		document.execCommand("copy");
		document.body.removeChild(el);
		alert(`Copied ${product.name} URL to clipboard`);
	});
};

/**
 * @description Function to re-render the product configuration options HTML when a configuration option is changed
 */
const reRenderConfigurator = () => {
	/** @type {State} */
	const state = {
		bandwidth: $("input[name=radio-option-bandwidth]:checked").val(),
		channels: $("input[name=radio-option-channels]:checked").val(),
		MSO: $(".configuration-button-mso").hasClass("active") ? true : false,
	};

	/** @type {ProductDetails} */
	const foundProduct = products.find(
		(product) => product.bandwidth === state.bandwidth && product.channels === state.channels && (state.MSO ? product.mso : !product.mso)
	);

	if (!foundProduct?.sku) throw new Error("foundProduct: No product found");

	if (!viewedProducts.includes(foundProduct.sku)) {
		viewedProducts.push(foundProduct.sku);
		const stock_lvl = document.querySelector('.pico-stock_message').getAttribute('data-stock');

		dataLayer.push({
			event: "view_item",
			ecommerce: {
				currency: $.cookie("exp__currency"),
				value: "0.00",
				items: [
					{
						item_id: foundProduct.sku,
						item_url: $(location).attr("href"),
						item_name: foundProduct.name,
						price: foundProduct.price_value,
						quantity: "1",
						stock_av: stock_lvl,
					},
				],
			},
		});
	}

	const currentUrl = window.location.href?.split("?")[0];
	history.pushState({}, "", `${currentUrl}?kit=${foundProduct.model}`);

	/** @description Build the product configurator HTML */
	buildConfigurator(foundProduct).catch((error) => {
		throw new Error(error.message);
	});
};

/**
 * @description Function to build the product configuration options HTML
 *
 * @param {ProductDetails} product - The product details to build the HTML from
 * @returns {Promise<void>}
 */
const buildConfigurator = async (product) => {
	if (!product?.sku) throw new Error("buildConfigurator: No product found", product);

	/** @description Build the product configurator HTML */
	await $(".pico-configurator").html(`
		<p class="pico-configurator_title">Configure Your Scope</p>
		<div class="pico-configurator_grid">
			${configurationOptions
				.map(
					(option) => `
					<div${option.class ? ` class="${option.class}"` : ""}>
						<p class="pico-configurator_label">${option.label}</p>
						${buildConfigurationOptions(option, product[option.name])}
					</div>
					`
				)
				.join("")}
			${buildProductInformation(product)}
			${buildPriceAndStock(product)}
		</div>
	`);

	await renderProductImage(product.image ?? "");
	await addDataLayerClickEvent(product);
	await renderShareButton(product);
	$("input[name='entry_id']").val(product.entry_id);

	$(".pico-configurator input").on("click", (event) => {
		const { name, value } = event.target;
		/** @type {string} */
		const shortName = event.target?.id?.split("-")[2] ?? "";

		if (event.target.id.includes("checkbox-option")) {
			if ($(`.configuration-button-${shortName}`).hasClass("active")) {$(`.configuration-button-${shortName}`).removeClass("active");
				$(`.configuration-button-${shortName} input`).prop("checked", false);
			} else {$(`.configuration-button-${shortName}`).addClass("active");
				$(`.configuration-button-${shortName} input`).prop("checked", true);
			}
		} else {$(`.configuration-button-${name}`).removeClass("active");
			$(`.configuration-button-${name} input`).prop("checked", false);
			$(`.configuration-button-${name}[for=${event.target.id}]`).addClass("active");
			$(`.configuration-button-${name}[for=${event.target.id}] input`).prop("checked", true);
		}

		reRenderConfigurator();
	});
};

/**
 * @description Initialise function to handle the loading of the JSON files and the building of the product configuration options
 *
 * @returns {Promise<void>}
 */
const init = async () => {
	/* @description Pick the correct JSON file based on the currency cookie */
	switch ($.cookie("exp__currency")) {
		case "US":
			jsonFile = "/json/3000_json_us";
			break;
		case "EU":
			jsonFile = "/json/3000_json_eu";
			break;
		case "GB":
		default:
			jsonFile = "/json/3000_json_gb";
			break;
	}
	/* @description Pick the correct JSON stock file based on the location cookie */
	switch ($.cookie("exp__geomodal")) {
		case "US":
			jsonStockFile = "/json/stk_lvl-3000_us";
			break;
		case "GB":
		default:
			jsonStockFile = "/json/stk_lvl-3000_gb";
			break;
	}

	/* @description Fetch the data from the JSON files */
	try {
		/** @type {ProductStock[]} */
		const productStock = await fetch(jsonStockFile)
			.then((response) => response.json())
			.then((data) => data?.stk_lvl ?? [])
			.catch((error) => {
				throw new Error(error.message);
			});

		products = await fetch(jsonFile)
			.then((response) => response.json())
			.then((data) => {
				if (!data?.priceData?.length) throw new Error("No products found");
				return data.priceData.map((product) => ({
					...product,
					stock: parseInt(productStock.find((stock) => stock.entid === product.entry_id)?.stock ?? 0),
					image: productImages.find((image) => image.entry_ids.includes(product.entry_id))?.path ?? "",
				}));
			})
			.catch((error) => {
				throw new Error(error.message);
			});
	} catch (error) {
		throw new Error(error.message);
	}

	/** @description Build the product configuration options from the JSON data */
	configurationOptions = [
		{
			name: "bandwidth",
			label: "Bandwidth <span>(MHz)</span>",
			type: "radio",
			class: "pico-grid_span_2",
			options: await products
				.map((product) => ({
					key: product.bandwidth,
					// disabled: product.stock === 0,
				}))
				.filter((product, index, self) => index === self.findIndex((t) => t.key === product.key))
				.sort((a, b) => parseFloat(a.key) - parseFloat(b.key)),
		},
		{
			name: "channels",
			label: "Channels",
			type: "radio",
			options: await products
				.map((product) => ({
					key: product.channels,
					// disabled: product.stock === 0,
				}))
				.filter((product, index, self) => index === self.findIndex((t) => t.key === product.key))
				.sort((a, b) => parseFloat(a.key) - parseFloat(b.key)),
		},
		{
			name: "mso",
			label: "MSO",
			type: "checkbox",
			options: (await products.find((product) => product.mso))
				? {
						key: "MSO",
						disabled: false,
				  }
				: {
						key: "MSO",
						disabled: true,
				  },
		},
	];

	/** @type {number | undefined} */
	let productIndex;
	/** @type {string | undefined} */
	const selectedProduct = getQueryStringValue("kit");

	if (selectedProduct?.length) {
		productIndex = products.findIndex((product) => product.model.toLowerCase() === selectedProduct.toLowerCase()) ?? undefined;
	}

	const findInStockLowest = () => {
		/** @type {ProductDetails} */
		let productsInStock = products.reduce((acc, product) => {
			if (product.stock > 0) {acc.push(product);}
			return acc;
		}, []);
		if (!productsInStock.length) {
			productsInStock = products;
		}
		return productsInStock.sort((a, b) => parseFloat(a.price_value) - parseFloat(b.price_value))[0];
	};

	/** @type {ProductDetails} */
	const defaultProduct =
		productIndex !== undefined && productIndex > -1
			? products[productIndex]
			: findInStockLowest() ?? products.sort((a, b) => parseFloat(a.price_value) - parseFloat(b.price_value))[0];

	/** @description Build the product configuration options HTML */
	await buildConfigurator(defaultProduct).catch((error) => {
		throw new Error(error.message);
	});

	viewedProducts.push(defaultProduct.sku);
	const stock_lvl = document.querySelector('.pico-stock_message').getAttribute('data-stock');

	dataLayer.push({
		event: "view_item",
		ecommerce: {
			currency: $.cookie("exp__currenCook"),
			value: "0.00",
			items: [
				{
					item_id: defaultProduct.sku,
					item_url: $(location).attr("href"),
					item_name: defaultProduct.name,
					price: defaultProduct.price_value,
					quantity: "1",
					stock_av: stock_lvl,
				},
			],
		},
	});
};

/**
 * @description Run the init function on page load
 */
document.addEventListener("DOMContentLoaded", async () => {
	await init().catch((error) => {
		console.error(`An error occurred: ${error.message}`);
	});
});

$(window).scroll(function () {
	if ($(this).scrollTop() > 100) {$(".scrollup").fadeIn();} else {$(".scrollup").fadeOut();}
});
$(function () {
	$(".scrollup").click(function () {
		$("html, body").animate(
			{
				scrollTop: 0,
			},
			600
		);
		return false;
	});
});
$(document).ready(function () {
	$(".fancybox").fancybox({
		openEffect: "fade",
		openSpeed: 150,
		closeEffect: "fade",
		closeSpeed: 150,
		aspectRatio: true,
		scrolling: "no",
		helpers: {
			title: {
				type: "inside",
			},
			overlay: {
				css: {
					background: "rgba(87,120,165,0.55)",
				},
			},
		},
	});
});
$("a.zoom").append("<span></span>");
$(function () {
	$(".popover-link")
		.popover({
			html: true,
			placement: "right",
		})
		.click(function (e) {e.preventDefault();});

	$(":not(#anything)").on("click", function (e) {
		$(".popover-link").each(function () {
			//the 'is' for buttons that trigger popups
			//the 'has' for icons and other elements within a button that triggers a popup
			if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $(".popover").has(e.target).length === 0) {
				$(this).popover("hide");
				return;
			}
		});
	});
});
$(".accsTabs li:first").addClass("active");
$(".tab-pane:first").addClass("active");

//Reviews product selector
$("select#prod_id").on("change", function () {
	$(".hiddenFields input[name='entry_id']").val(this.value);
});

$("#msomap li a").click(function (e) {e.preventDefault();});
