/**
 * DataStream admin dashboard: one health card per stream, then the records
 * browser. All values go through textContent.
 */
( function ( wp ) {
	'use strict';

	const apiFetch = wp.apiFetch;
	const labels   = window.datastreamAdmin ? datastreamAdmin.labels : {};

	const state = {
		loading: true,
		syncing: '',
		error: '',
		notice: '',
		status: null,
		streams: [],
		records: [],
		browsing: '',
	};

	function setText( el, text ) {
		el.textContent = text;
	}

	function createEl( tag, className, text ) {
		const el = document.createElement( tag );

		if ( className ) {
			el.className = className;
		}

		if ( text ) {
			setText( el, text );
		}

		return el;
	}

	function formatDate( value ) {
		if ( ! value ) {
			return labels.never || 'Never';
		}

		const date = new Date( value );

		if ( Number.isNaN( date.getTime() ) ) {
			return value;
		}

		return date.toLocaleString();
	}

	function timeAgo( unixSeconds ) {
		if ( ! unixSeconds ) {
			return labels.never || 'Never';
		}

		const seconds = Math.max( 0, Math.floor( Date.now() / 1000 ) - unixSeconds );

		if ( seconds < 90 ) {
			return ( labels.justNow || 'just now' );
		}
		if ( seconds < 3600 ) {
			return Math.round( seconds / 60 ) + ( labels.minAgo || ' min ago' );
		}
		if ( seconds < 86400 ) {
			return Math.round( seconds / 3600 ) + ( labels.hourAgo || ' h ago' );
		}
		return Math.round( seconds / 86400 ) + ( labels.dayAgo || ' d ago' );
	}

	async function fetchAll() {
		state.loading = true;
		state.error   = '';
		render();

		try {
			const [ status, streams, data ] = await Promise.all( [
				apiFetch( { path: '/datastream/v1/status' } ),
				apiFetch( { path: '/datastream/v1/streams' } ),
				apiFetch( { path: '/datastream/v1/ingested-data?limit=50' + ( state.browsing ? '&stream_type=' + encodeURIComponent( state.browsing ) : '' ) } ),
			] );

			state.status  = status;
			state.streams = streams.streams || [];
			state.records = data.records || [];
		} catch ( error ) {
			state.error = labels.error || 'Could not load records.';
			console.error( 'DataStream: failed to load records.', error );
		} finally {
			state.loading = false;
			render();
		}
	}

	async function triggerSync( streamId ) {
		state.syncing = streamId || 'all';
		state.notice  = '';
		state.error   = '';
		render();

		try {
			const result = await apiFetch( {
				path: '/datastream/v1/sync' + ( streamId ? '?stream=' + encodeURIComponent( streamId ) : '' ),
				method: 'POST',
			} );

			if ( result.success ) {
				state.notice = ( labels.syncSuccess || 'Sync completed.' ) + ' (' + ( result.processed || 0 ) + ')';
			} else {
				state.error = result.message || ( labels.syncFailed || 'Sync failed.' );
			}
		} catch ( error ) {
			state.error = labels.syncFailed || 'Sync failed.';
			console.error( 'DataStream: sync failed.', error );
		} finally {
			state.syncing = '';
			await fetchAll();
		}
	}

	function renderStreamCard( stream ) {
		const counts = ( state.status && state.status.stream_counts ) || {};
		const card   = createEl( 'div', 'datastream-stream-card' + ( stream.enabled ? '' : ' is-paused' ) );

		const head = createEl( 'div', 'datastream-stream-card-head' );
		head.appendChild( createEl( 'strong', '', stream.label || stream.id ) );

		const dots = createEl( 'span', 'datastream-dots' );
		( stream.history || [] ).forEach( function ( ok ) {
			dots.appendChild( createEl( 'i', 'datastream-dot ' + ( ok ? 'is-ok' : 'is-bad' ) ) );
		} );
		head.appendChild( dots );
		card.appendChild( head );

		const meta = createEl( 'p', 'datastream-stream-card-meta' );
		meta.appendChild( document.createTextNode(
			String( counts[ stream.id ] || 0 ) + ' ' + ( labels.records || 'records' ) + ' · ' +
			( labels.updated || 'updated' ) + ' ' + timeAgo( stream.last_sync_at )
		) );
		card.appendChild( meta );

		if ( ! stream.enabled ) {
			card.appendChild( createEl( 'p', 'datastream-stream-card-note', labels.paused || 'Paused — not syncing.' ) );
		} else if ( stream.backoff_until && stream.backoff_until * 1000 > Date.now() ) {
			const until = new Date( stream.backoff_until * 1000 );
			card.appendChild( createEl(
				'p',
				'datastream-stream-card-note is-warn',
				( stream.last_message || ( labels.failing || 'The last sync failed.' ) ) + ' ' +
				( labels.retryAt || 'Retrying at' ) + ' ' + until.toLocaleTimeString() + '.'
			) );
		} else if ( false === stream.last_success && stream.last_message ) {
			card.appendChild( createEl( 'p', 'datastream-stream-card-note is-warn', stream.last_message ) );
		}

		const actions = createEl( 'p', 'datastream-stream-card-actions' );

		const syncBtn = createEl( 'button', 'button button-small', state.syncing === stream.id ? ( labels.working || 'Working…' ) : ( labels.syncNow || 'Sync Now' ) );
		syncBtn.type = 'button';
		syncBtn.disabled = '' !== state.syncing;
		syncBtn.addEventListener( 'click', function () {
			triggerSync( stream.id );
		} );
		actions.appendChild( syncBtn );

		const browseBtn = createEl( 'button', 'button button-small', state.browsing === stream.id ? ( labels.browseAll || 'Show all records' ) : ( labels.browse || 'Browse records' ) );
		browseBtn.type = 'button';
		browseBtn.addEventListener( 'click', function () {
			state.browsing = state.browsing === stream.id ? '' : stream.id;
			fetchAll();
		} );
		actions.appendChild( browseBtn );

		const edit = createEl( 'a', 'button button-small', labels.edit || 'Edit' );
		edit.href = ( window.datastreamAdmin && datastreamAdmin.settingsUrl ? datastreamAdmin.settingsUrl : 'admin.php?page=datastream-settings&tab=streams' ) + '&stream=' + encodeURIComponent( stream.id );
		actions.appendChild( edit );

		card.appendChild( actions );

		return card;
	}

	function renderTable( container ) {
		if ( ! state.records.length ) {
			const empty = createEl( 'div', 'datastream-empty' );
			empty.appendChild( createEl( 'p', '', labels.empty || 'No records yet.' ) );
			container.appendChild( empty );
			return;
		}

		const heading = createEl( 'h2', '', ( labels.recordsHeading || 'Records' ) + ( state.browsing ? ' — ' + state.browsing : '' ) );
		container.appendChild( heading );

		const tableWrap = createEl( 'div', 'datastream-table-wrap' );
		const table     = createEl( 'table', 'datastream-table widefat striped' );
		const thead     = createEl( 'thead' );
		const headRow   = createEl( 'tr' );

		[ 'ID', labels.stream || 'Stream', labels.updatedCol || 'Updated', labels.payload || 'Record' ].forEach( function ( heading2 ) {
			headRow.appendChild( createEl( 'th', '', heading2 ) );
		} );

		thead.appendChild( headRow );
		table.appendChild( thead );

		const tbody = createEl( 'tbody' );

		state.records.forEach( function ( record ) {
			const row = createEl( 'tr' );

			row.appendChild( createEl( 'td', '', record.external_id || '' ) );
			row.appendChild( createEl( 'td', '', record.stream_type || '' ) );
			row.appendChild( createEl( 'td', '', formatDate( record.updated_at ) ) );

			const payloadCell = createEl( 'td' );
			const toggleBtn   = createEl( 'button', 'button button-small datastream-payload-toggle', labels.viewPayload || 'View' );
			const payload     = createEl( 'pre', 'datastream-payload' );

			toggleBtn.type = 'button';
			toggleBtn.addEventListener( 'click', function () {
				const isOpen = payload.classList.toggle( 'is-open' );
				setText( toggleBtn, isOpen ? ( labels.hidePayload || 'Hide' ) : ( labels.viewPayload || 'View' ) );
			} );

			setText( payload, JSON.stringify( record.data || {}, null, 2 ) );

			payloadCell.appendChild( toggleBtn );
			payloadCell.appendChild( payload );
			row.appendChild( payloadCell );

			tbody.appendChild( row );
		} );

		table.appendChild( tbody );
		tableWrap.appendChild( table );
		container.appendChild( tableWrap );
	}

	function render() {
		const container = document.getElementById( 'datastream-dashboard' );

		if ( ! container ) {
			return;
		}

		container.innerHTML = '';

		if ( state.loading ) {
			const loading = createEl( 'div', 'datastream-loading' );
			loading.appendChild( createEl( 'span', 'spinner is-active' ) );
			loading.appendChild( createEl( 'p', '', labels.loading || 'Loading records…' ) );
			container.appendChild( loading );
			return;
		}

		if ( state.error ) {
			container.appendChild( createEl( 'div', 'datastream-notice is-error', state.error ) );
		}

		if ( state.notice ) {
			container.appendChild( createEl( 'div', 'datastream-notice is-success', state.notice ) );
		}

		if ( state.status && state.status.warnings && state.status.warnings.length ) {
			const warn = createEl( 'div', 'datastream-notice is-info' );
			setText( warn, state.status.warnings.join( ' ' ) );
			container.appendChild( warn );
		}

		if ( ! state.streams.length ) {
			// No streams yet: the dashboard's job is to start the wizard.
			const empty = createEl( 'div', 'datastream-hero-empty' );
			empty.appendChild( createEl( 'h2', '', labels.heroTitle || 'Connect your first API' ) );
			empty.appendChild( createEl( 'p', '', labels.heroBody || 'Paste an address, and your data appears on your site.' ) );
			const cta = createEl( 'a', 'button button-primary button-hero', labels.heroCta || 'Open the Connect Wizard' );
			cta.href = ( window.datastreamAdmin && datastreamAdmin.settingsUrl ) ? datastreamAdmin.settingsUrl : 'admin.php?page=datastream-settings&tab=streams';
			empty.appendChild( cta );
			container.appendChild( empty );
			return;
		}

		const meta = createEl( 'p', 'datastream-toolbar' );
		const next = state.status && state.status.next_sync ? formatDate( state.status.next_sync + ' UTC' ) : ( labels.notScheduled || 'Not scheduled' );
		meta.appendChild( document.createTextNode( ( labels.nextSync || 'Next scheduled sync' ) + ': ' + next + ' ' ) );

		const syncAll = createEl( 'button', 'button', state.syncing ? ( labels.working || 'Working…' ) : ( labels.syncAll || 'Sync all now' ) );
		syncAll.type = 'button';
		syncAll.disabled = '' !== state.syncing;
		syncAll.addEventListener( 'click', function () {
			triggerSync( '' );
		} );
		meta.appendChild( syncAll );
		container.appendChild( meta );

		const cards = createEl( 'div', 'datastream-stream-cards' );
		state.streams.forEach( function ( stream ) {
			cards.appendChild( renderStreamCard( stream ) );
		} );
		container.appendChild( cards );

		renderTable( container );
	}

	document.addEventListener( 'DOMContentLoaded', fetchAll );
} )( window.wp );
