/**
 * Trending News front-end behaviour.
 *
 * The classic theme used FlexSlider for the hero, the ticker, the front-page
 * carousel, the Theme TV strip, the "Featured category" tab slider and the
 * sidebar tabber. This is the same behaviour in plain JS with no stylesheet of
 * its own — it only toggles inline display/opacity and scroll position on
 * blocks the templates already define.
 *
 * Every function is defensive: if the blocks it drives are not present (or a
 * section has not been rebuilt yet) it returns without touching the DOM, so a
 * template change can never leave the page in a half-initialised state.
 */
( function () {
	'use strict';

	function byId( id ) {
		return document.getElementById( id );
	}

	/**
	 * True when the element is a real scroll container with something to
	 * scroll. `overflow: hidden` counts — it is programmatically scrollable —
	 * but `visible` and `clip` do not.
	 */
	function isScrollable( el ) {
		if ( ! el ) {
			return false;
		}
		var overflowX = window.getComputedStyle( el ).overflowX;
		if ( overflowX === 'visible' || overflowX === 'clip' ) {
			return false;
		}
		return ( el.scrollWidth - el.clientWidth ) > 1;
	}

	/* ------------------------------------------------------------------ *
	 * Hero slider (parts/hero.html)
	 * ------------------------------------------------------------------ */
	function heroSlider() {
		var main = byId( 'block_hr-mainquery' );
		var thumbs = byId( 'block_hr-thumbquery' );
		if ( ! main || ! thumbs ) {
			return;
		}
		var slides = main.querySelectorAll( '.wp-block-post-template > li' );
		var picks = thumbs.querySelectorAll( '.wp-block-post-template > li' );
		if ( slides.length < 2 ) {
			return;
		}
		var current = 0;
		var timer;

		function show( i ) {
			current = ( i + slides.length ) % slides.length;
			for ( var s = 0; s < slides.length; s++ ) {
				slides[ s ].style.display = s === current ? '' : 'none';
			}
			for ( var p = 0; p < picks.length; p++ ) {
				picks[ p ].style.opacity = p === current ? '1' : '';
			}
		}

		function play() {
			clearInterval( timer );
			timer = setInterval( function () {
				show( current + 1 );
			}, 8000 );
		}

		for ( var t = 0; t < picks.length; t++ ) {
			( function ( index ) {
				picks[ index ].addEventListener( 'click', function ( e ) {
					e.preventDefault();
					show( index );
					play();
				} );
				picks[ index ].style.cursor = 'pointer';
			} )( t );
		}

		show( 0 );
		play();
	}

	/* ------------------------------------------------------------------ *
	 * News ticker (parts/header.html) — classic slideshowSpeed: 8000
	 * ------------------------------------------------------------------ */
	function ticker() {
		var query = byId( 'block_hd-tickerquery' );
		if ( ! query ) {
			return;
		}
		var items = query.querySelectorAll( '.wp-block-post-template > li' );
		if ( items.length < 2 ) {
			return;
		}
		var current = 0;
		var timer;

		function show( i ) {
			current = ( i + items.length ) % items.length;
			for ( var s = 0; s < items.length; s++ ) {
				items[ s ].style.display = s === current ? '' : 'none';
			}
		}

		function play() {
			clearInterval( timer );
			timer = setInterval( function () {
				show( current + 1 );
			}, 8000 );
		}

		var nav = byId( 'block_hd-tickernav' );
		if ( nav ) {
			var arrows = nav.querySelectorAll( 'p' );
			if ( arrows.length >= 2 ) {
				bindClick( arrows[ 0 ], function () {
					show( current - 1 );
					play();
				} );
				bindClick( arrows[ 1 ], function () {
					show( current + 1 );
					play();
				} );
			}
		}

		show( 0 );
		play();
	}

	/* ------------------------------------------------------------------ *
	 * Horizontal strips: front-page carousel + Theme TV "browse more"
	 * ------------------------------------------------------------------ */

	/**
	 * Glide an element's scrollLeft by `delta`, clamped to its own extent.
	 *
	 * scrollBy({behavior:'smooth'}) is silently ignored on an overflow:hidden
	 * box (verified on the live page: `behavior:'auto'` and a direct
	 * scrollLeft assignment both move it, `behavior:'smooth'` does not), so the
	 * easing is done here instead. Repeat clicks cancel the previous run rather
	 * than fighting it.
	 */
	function animateScrollBy( el, delta, duration ) {
		var start = el.scrollLeft;
		var max = Math.max( 0, el.scrollWidth - el.clientWidth );
		var target = Math.min( max, Math.max( 0, start + delta ) );
		if ( target === start ) {
			return;
		}
		el.tnScrollRun = ( el.tnScrollRun || 0 ) + 1;
		var run = el.tnScrollRun;
		if ( ! window.requestAnimationFrame ) {
			el.scrollLeft = target;
			return;
		}
		var began = null;
		var settled = false;
		function frame( now ) {
			if ( el.tnScrollRun !== run ) {
				return;
			}
			if ( began === null ) {
				began = now;
			}
			var progress = Math.min( 1, ( now - began ) / duration );
			var eased = progress < 0.5
				? 2 * progress * progress
				: -1 + ( 4 - ( 2 * progress ) ) * progress;
			el.scrollLeft = start + ( ( target - start ) * eased );
			if ( progress < 1 ) {
				window.requestAnimationFrame( frame );
			} else {
				settled = true;
			}
		}
		window.requestAnimationFrame( frame );
		// rAF is suspended in hidden/prerendered tabs and throttled by
		// battery-saver modes; the click must still land somewhere. If the
		// animation has not finished shortly after it should have, jump
		// straight to the target (nobody is watching the easing anyway).
		window.setTimeout( function () {
			if ( el.tnScrollRun === run && ! settled ) {
				el.tnScrollRun++;
				el.scrollLeft = target;
			}
		}, duration + 200 );
	}

	function bindClick( el, fn ) {
		if ( ! el ) {
			return;
		}
		el.style.cursor = 'pointer';
		el.addEventListener( 'click', function ( e ) {
			// Also cancels the inner <a href="#"> when the click bubbles up.
			e.preventDefault();
			fn();
		} );
	}

	/**
	 * Wire prev/next arrows to a strip that lives inside an overflow:hidden
	 * viewport. The viewport is the scroll container (overflow:hidden elements
	 * are programmatically scrollable); if for any reason it is not, the strip
	 * itself is tried, and finally the strip is translated instead — so the
	 * arrows move something in every case.
	 *
	 * @param {string} viewportId Element id of the clipping viewport.
	 * @param {string} prevId     Element id of the "previous" arrow.
	 * @param {string} nextId     Element id of the "next" arrow.
	 * @param {number} step       Pixels per click (classic flexslider move: 2).
	 * @param {string} navId      Optional wrapper id to find the arrows in when
	 *                            prevId/nextId are absent.
	 */
	function strip( viewportId, prevId, nextId, step, navId ) {
		var viewport = byId( viewportId );
		if ( ! viewport ) {
			return;
		}

		var prev = byId( prevId );
		var next = byId( nextId );
		if ( ( ! prev || ! next ) && navId ) {
			var nav = byId( navId );
			if ( nav ) {
				var arrows = nav.querySelectorAll( 'p' );
				if ( arrows.length >= 2 ) {
					prev = prev || arrows[ 0 ];
					next = next || arrows[ 1 ];
				}
			}
		}
		if ( ! prev || ! next ) {
			return;
		}

		var rail = viewport.querySelector( '.wp-block-post-template' ) || viewport.firstElementChild;
		var offset = 0;

		function move( direction ) {
			var scroller = isScrollable( viewport ) ? viewport : ( isScrollable( rail ) ? rail : null );
			if ( scroller ) {
				animateScrollBy( scroller, direction * step, 400 );
				return;
			}
			if ( ! rail ) {
				return;
			}
			// Last resort: slide the rail itself, clamped to its own width.
			var max = Math.max( 0, rail.scrollWidth - viewport.clientWidth );
			offset = Math.min( max, Math.max( 0, offset + ( direction * step ) ) );
			rail.style.transition = 'transform .4s ease';
			rail.style.transform = 'translateX(-' + offset + 'px)';
		}

		bindClick( prev, function () {
			move( -1 );
		} );
		bindClick( next, function () {
			move( 1 );
		} );
	}

	/* ------------------------------------------------------------------ *
	 * Panel switchers (tab strips)
	 * ------------------------------------------------------------------ */

	/**
	 * Generic tab strip: click tab N, show panel N and hide the rest.
	 *
	 * @param {string}   navId    Element id holding one <p> per tab.
	 * @param {string[]} tabIds   Element ids of the tabs (may be empty — the
	 *                            <p> children of navId are then used).
	 * @param {string[]} panelIds Element ids of the panels, in the same order.
	 * @param {Function} onSwitch Optional callback( tabs, index ).
	 */
	function tabStrip( navId, tabIds, panelIds, onSwitch ) {
		var nav = byId( navId );
		if ( ! nav ) {
			return;
		}

		var panels = [];
		var i;
		for ( i = 0; i < panelIds.length; i++ ) {
			var panel = byId( panelIds[ i ] );
			if ( panel ) {
				panels.push( panel );
			}
		}
		// Nothing to switch between: leave the links doing whatever they do.
		if ( panels.length < 2 ) {
			return;
		}

		var tabs = [];
		for ( i = 0; i < tabIds.length; i++ ) {
			var tab = byId( tabIds[ i ] );
			if ( tab ) {
				tabs.push( tab );
			}
		}
		if ( tabs.length < panels.length ) {
			tabs = Array.prototype.slice.call( nav.querySelectorAll( 'p' ) );
		}
		if ( tabs.length < panels.length ) {
			return;
		}

		// Remember how the first (visible) panel lays itself out, so showing a
		// panel restores that display value rather than guessing.
		var shown = window.getComputedStyle( panels[ 0 ] ).display;
		if ( ! shown || shown === 'none' ) {
			shown = 'flex';
		}

		function show( index ) {
			for ( var p = 0; p < panels.length; p++ ) {
				panels[ p ].style.display = p === index ? shown : 'none';
			}
			for ( var t = 0; t < panels.length; t++ ) {
				tabs[ t ].setAttribute( 'aria-selected', t === index ? 'true' : 'false' );
			}
			if ( typeof onSwitch === 'function' ) {
				onSwitch( tabs, index );
			}
		}

		for ( i = 0; i < panels.length; i++ ) {
			( function ( index ) {
				bindClick( tabs[ index ], function () {
					show( index );
				} );
			} )( i );
		}

		show( 0 );
	}

	/**
	 * "Featured category" tabs (Gadgets / Movies / Gaming) on the front page.
	 * The classic used the three anchors as flexslider manualControls, so the
	 * panel swaps in place instead of navigating to the category archive.
	 */
	function featuredCategoryTabs() {
		tabStrip(
			'block_fp-fc-tabs',
			[ 'block_fp-fc-tabs-1', 'block_fp-fc-tabs-2', 'block_fp-fc-tabs-3' ],
			[ 'block_fp-fc-row', 'block_fp-fc-row-2', 'block_fp-fc-row-3' ]
		);
	}

	/**
	 * Sidebar tabber (Latest / Popular / Comments). The classic marked the
	 * active tab with `ul.tabs li.active {background:#000}` and
	 * `.tabs li.active h4 a {color:#FFF}` — reproduced here as inline state,
	 * the same way the hero marks its active thumbnail.
	 */
	function sidebarTabs() {
		tabStrip(
			'block_sb-tabs',
			[ 'block_sb-tab-1', 'block_sb-tab-2', 'block_sb-tab-3' ],
			[ 'block_sb-tab-pane-1', 'block_sb-tab-pane-2', 'block_sb-tab-pane-3' ],
			function ( tabs, index ) {
				for ( var t = 0; t < tabs.length; t++ ) {
					var active = t === index;
					tabs[ t ].style.backgroundColor = active ? '#000000' : '';
					tabs[ t ].style.color = active ? '#FFFFFF' : '';
					var link = tabs[ t ].querySelector( 'a' );
					if ( link ) {
						link.style.color = active ? '#FFFFFF' : '';
					}
				}
			}
		);
	}

	function settingsPanel() {
		// The stepfox render filter prefixes anchors, so the DOM ids are
		// block_theme-settings / block_settings-button.
		var panel = byId( 'block_theme-settings' ) || byId( 'theme-settings' );
		var btn = byId( 'block_settings-button' ) || byId( 'settings-button' );
		if ( ! panel || ! btn ) {
			return;
		}

		var open = false;
		btn.addEventListener( 'click', function () {
			open = ! open;
			panel.style.right = open ? '0px' : '-250px';
		} );

		function inject( css ) {
			var s = document.createElement( 'style' );
			s.textContent = css;
			document.head.appendChild( s );
		}

		// Classic TN-settings action palette. gradient1 applies #dd3333 even
		// though the swatch itself is painted #f11800 — quirk preserved.
		var colors = [ '#dd3333', '#235a8d', '#0a6708', '#109cc4', '#000000', '#dc4e00', '#560547', '#b2b2b2' ];

		function bind( sectionClass, makeCss ) {
			var section = panel.querySelector( '.' + sectionClass );
			if ( ! section ) {
				return;
			}
			for ( var i = 0; i < colors.length; i++ ) {
				( function ( c, n ) {
					var sw = section.querySelector( '.gradient' + n );
					if ( sw ) {
						sw.addEventListener( 'click', function () {
							inject( makeCss( c ) );
						} );
					}
				} )( colors[ i ], i + 1 );
			}
		}

		bind( 'header-color', function ( c ) {
			return '#block_hd-logorow{background-color:' + c + ' !important}';
		} );
		bind( 'menu-footer-color', function ( c ) {
			return '#block_hd-navbar{background-color:' + c + ' !important}' +
				'#block_footer-widgets{background-color:' + c + ' !important}' +
				'#block_hd-me-panel,#block_hd-mm-panel{border-color:' + c + ' !important}';
		} );
		bind( 'widget-border-color', function ( c ) {
			return 'h3.wp-block-heading{border-color:' + c + ' !important}';
		} );
		bind( 'symbol-color', function ( c ) {
			return 'a:hover{color:' + c + ' !important}' +
				'.tn-review-score{background-color:' + c + ' !important}' +
				'.tn-firstcat a{color:' + c + ' !important}' +
				'.wp-block-post-terms a{color:' + c + ' !important}' +
				'#block_hd-datevalue{color:' + c + ' !important}';
		} );

		var black = panel.querySelector( '.black-title' );
		var white = panel.querySelector( '.white-title' );
		if ( black ) {
			black.addEventListener( 'click', function () {
				inject( '#block_hd-mainnav .wp-block-navigation-item__content{color:#000000 !important}' );
			} );
		}
		if ( white ) {
			white.addEventListener( 'click', function () {
				inject( '#block_hd-mainnav .wp-block-navigation-item__content{color:#FFFFFF !important}' );
			} );
		}

		// Classic behavior: "Sidebar Right" floats the content right, which
		// puts the sidebar on the left (inverted labels preserved as-is).
		var mains = [ 'block_fp-main', 'block_ix-main', 'block_sg-main', 'block_ar-main', 'block_pg-main', 'block_se-main', 'block_nf-main' ];
		var radios = panel.querySelectorAll( '.rg' );
		for ( var r = 0; r < radios.length; r++ ) {
			radios[ r ].addEventListener( 'change', function () {
				var r2 = byId( 'r2' );
				var reverse = r2 && r2.checked;
				for ( var m = 0; m < mains.length; m++ ) {
					var el = byId( mains[ m ] );
					if ( el ) {
						el.style.flexDirection = reverse ? 'row-reverse' : 'row';
					}
				}
			} );
		}
	}

	function init() {
		heroSlider();
		ticker();
		// 330px = classic flexslider move:2 x (itemWidth 141 + itemMargin 24).
		strip( 'block_fp-car-query', 'block_fp-car-nav-1', 'block_fp-car-nav-2', 330, 'block_fp-car-nav' );
		strip( 'block_tv-morequery', 'block_tv-prev', 'block_tv-next', 330, 'block_tv-arrows' );
		featuredCategoryTabs();
		sidebarTabs();
		settingsPanel();
	}

	if ( document.readyState === 'loading' ) {
		document.addEventListener( 'DOMContentLoaded', init );
	} else {
		init();
	}
} )();
