import {
	type AdminData,
	type AdminRecord,
	field,
	featureAvailable,
	featureLockReason,
	firstOf,
	launchHealth,
	launchNeedsReview,
	numberValue,
	statusLabel,
	textValue,
} from './admin-data';
import type { ConfirmAttributeConfig } from './confirmations';
import { confirmAttributes } from './confirmations';

export interface DetailFact {
	label: string;
	value: string;
}

export interface DetailNextStep {
	title: string;
	body: string;
	tone: 'ready' | 'warning' | 'danger' | 'neutral';
}

export interface FriendlyStatusCard {
	kicker: string;
	title: string;
	body: string;
	tone: 'success' | 'running' | 'failed' | 'scheduled';
	confetti: boolean;
}

export const DetailActionForm = ( {
	data,
	uuid,
	action,
	label,
	capability,
	entitlement: entitlementKey = '',
	confirmation,
	disabledReason = '',
}: {
	data: AdminData;
	uuid: string;
	action: string;
	label: string;
	capability: string;
	entitlement?: string;
	confirmation?: ConfirmAttributeConfig;
	disabledReason?: string;
} ) => {
	const lockReason = featureLockReason(
		data,
		entitlementKey,
		capability,
		label
	);
	const disabled = Boolean( disabledReason || lockReason );

	return (
		<form
			method="post"
			action={ textValue( data.adminPostUrl ) }
			{ ...( confirmation ? confirmAttributes( confirmation ) : {} ) }
		>
			<input type="hidden" name="action" value={ action } />
			<input
				type="hidden"
				name="_wpnonce"
				value={ textValue( data.nonce ) }
			/>
			<input type="hidden" name="launch_uuid" value={ uuid } />
			<button
				type="submit"
				className="scds-button"
				disabled={
					disabled ||
					! featureAvailable( data, entitlementKey, capability )
				}
				title={ disabledReason || lockReason || undefined }
			>
				{ label }
			</button>
		</form>
	);
};

export const RowPreview = ( {
	rows,
	empty,
	titleKey,
	bodyKey,
}: {
	rows: AdminRecord[];
	empty: string;
	titleKey: string;
	bodyKey: string;
} ) => {
	if ( 0 === rows.length ) {
		return <p>{ empty }</p>;
	}

	return (
		<ul className="scds-detail-list">
			{ rows.slice( 0, 5 ).map( ( row, index ) => (
				<li key={ field( row, 'id', String( index ) ) }>
					<strong>{ rowPreviewTitle( row, titleKey ) }</strong>
					<span>{ rowPreviewBody( row, bodyKey ) }</span>
				</li>
			) ) }
		</ul>
	);
};

const rowPreviewTitle = ( row: AdminRecord, titleKey: string ): string =>
	'status' === titleKey && field( row, titleKey )
		? statusLabel( field( row, titleKey ) )
		: firstOf( row, [ titleKey, 'label', 'title', 'name' ], 'Item' );

const rowPreviewBody = ( row: AdminRecord, bodyKey: string ): string =>
	firstOf(
		row,
		[ bodyKey, 'summary', 'time', 'completedAt', 'startedAt', 'value' ],
		'Details will appear here when available.'
	);

export const detailSummary = ( launch: AdminRecord ): string =>
	hasCompletedRun( launch )
		? `${ lastResultText( launch ) }. ${ itemCountText(
				launch
		  ) } affected. Review recent activity and previous values below.`
		: `${ scheduleHeadlineText( launch ) }. ${ itemCountText(
				launch
		  ) } affected. ${
				launchNeedsReview( launch )
					? 'Review what needs attention before the live site changes.'
					: 'The safety check is clear.'
		  } Previous values will be saved where supported.`;

export const plainSummary = (
	launch: AdminRecord,
	operationCount: number,
	loadedTargetCount: number
): string => {
	const changeCount = operationCount || numberValue( launch.changeCount );
	const itemCount = loadedTargetCount || numberValue( launch.targetCount );
	const changeText =
		changeCount > 0
			? `${ changeCount } ${ 1 === changeCount ? 'change' : 'changes' }`
			: 'the changes saved in the safe copy';
	const itemText = itemCount > 0 ? itemCountText( launch ) : 'selected items';

	if ( hasCompletedRun( launch ) ) {
		if ( runNeedsAttention( launch ) ) {
			return `This scheduled change already ran and needs review. It affected ${ itemText }. Check recent activity and previous values before trying again.`;
		}

		return `This scheduled change already ran for ${ itemText }. Review what changed and any previous values before taking another action.`;
	}

	if ( launchNeedsReview( launch ) ) {
		return `This scheduled change has ${ changeText } for ${ itemText }. The live site has not changed. Review what needs attention before it goes live.`;
	}

	return `This scheduled change will apply ${ changeText } to ${ itemText }. The live site stays unchanged until the scheduled time.`;
};

export const detailFacts = ( launch: AdminRecord ): DetailFact[] => [
	{
		label: 'When',
		value: scheduleShortText( launch ),
	},
	{
		label: 'Items',
		value: itemCountText( launch ),
	},
	{
		label: 'Created by',
		value: field( launch, 'owner', 'Unknown owner' ),
	},
	{
		label: 'Last activity',
		value: lastResultText( launch ),
	},
	{
		label: 'Previous values',
		value: restoreRelevant( launch )
			? 'Review below'
			: 'Saved when possible',
	},
];

export const detailSummaryItems = ( launch: AdminRecord ): string[] => {
	if ( hasCompletedRun( launch ) ) {
		const items = [
			`Latest result: ${ lastResultText( launch ) }.`,
			`Affected ${ itemCountText( launch ) }.`,
		];

		items.push(
			restoreRelevant( launch )
				? 'Previous values can be reviewed below before anything is restored.'
				: 'Previous values are shown when WordPress has enough saved information.'
		);

		return items;
	}

	const items = [
		scheduleSentence( launch ),
		`Applies to ${ itemCountText( launch ) }.`,
		safetySentence( launch ),
	];

	if ( restoreRelevant( launch ) ) {
		items.push(
			'Previous values are available below before anything is restored.'
		);
	} else {
		items.push(
			'Previous values will be saved before the change goes live, where supported.'
		);
	}

	return items;
};

export const nextStepForLaunch = ( launch: AdminRecord ): DetailNextStep => {
	const lastRunStatus = field( launch, 'lastRunStatus' ).toLowerCase();

	if ( runNeedsAttention( launch ) ) {
		return {
			title:
				'rollback_failed' === lastRunStatus
					? 'Review the restore problem'
					: 'Review what needs attention',
			body:
				'rollback_failed' === lastRunStatus
					? 'WordPress could not finish restoring previous values. Check recent activity and previous values before retrying.'
					: 'Some or all changes could not be applied. Check recent activity and previous values before trying again.',
			tone: 'danger',
		};
	}

	if (
		[ 'successful', 'success', 'rolled_back' ].includes( lastRunStatus )
	) {
		return {
			title: 'Review the result',
			body: 'This scheduled change already ran. Check what changed and whether previous values can be restored.',
			tone: 'ready',
		};
	}

	const health = launchHealth( launch ).toLowerCase();

	if ( launchNeedsReview( launch ) || 'warning' === health ) {
		return {
			title: 'Review the safety check',
			body: 'The live site has not changed. Resolve the item below before this scheduled change goes live.',
			tone: 'warning',
		};
	}

	const status = field( launch, 'status' ).toLowerCase();

	if ( 'draft' === status ) {
		return {
			title: 'Choose when it should go live',
			body: 'Finish reviewing the safe copy, then schedule the date and time when this should update the site.',
			tone: 'neutral',
		};
	}

	if ( 'running' === status ) {
		return {
			title: 'Check progress',
			body: 'WordPress is applying this scheduled change. Recent activity will update when it finishes.',
			tone: 'warning',
		};
	}

	return {
		title: 'Ready for the scheduled time',
		body: 'You can still edit the schedule or cancel before it goes live. The live site stays unchanged until then.',
		tone: 'ready',
	};
};

export const friendlyStatusCard = (
	launch: AdminRecord
): FriendlyStatusCard => {
	const status = field( launch, 'status' ).toLowerCase();
	const lastRunStatus = field( launch, 'lastRunStatus' ).toLowerCase();
	const effective = lastRunStatus || status;

	if (
		[ 'successful', 'success', 'successful_with_warnings' ].includes(
			effective
		)
	) {
		return {
			kicker: 'Finished',
			title: 'Change completed',
			body: 'Everything ran cleanly. Restore remains nearby if needed.',
			tone: 'success',
			confetti: true,
		};
	}

	if ( 'rolled_back' === effective ) {
		return {
			kicker: 'Restored',
			title: 'Previous values restored',
			body: 'The live site was moved back to saved values. Review recent activity before changing it again.',
			tone: 'success',
			confetti: false,
		};
	}

	if ( 'running' === effective ) {
		return {
			kicker: 'Running',
			title: 'Change is running',
			body: 'WordPress is applying the saved change now. Recent activity will update when it finishes.',
			tone: 'running',
			confetti: false,
		};
	}

	if (
		[ 'failed', 'partially_failed', 'rollback_failed' ].includes(
			effective
		)
	) {
		return {
			kicker:
				'rollback_failed' === effective
					? 'Restore needs review'
					: 'Needs review',
			title:
				'partially_failed' === effective
					? 'Some changes need attention'
					: 'Change needs attention',
			body:
				'rollback_failed' === effective
					? 'WordPress could not finish restoring previous values. Check recent activity before retrying.'
					: 'The site was not fully updated. Check recent activity and saved previous values before retrying.',
			tone: 'failed',
			confetti: false,
		};
	}

	if ( 'cancelled' === effective ) {
		return {
			kicker: 'Stopped',
			title: 'Change canceled',
			body: 'This scheduled change will not run. Duplicate it as a draft if you need a new version.',
			tone: 'scheduled',
			confetti: false,
		};
	}

	if ( [ 'ready', 'draft' ].includes( effective ) ) {
		return {
			kicker: 'Draft',
			title: 'Review before scheduling',
			body: 'The live site has not changed. Finish the safety check, then choose a go-live time.',
			tone: 'scheduled',
			confetti: false,
		};
	}

	return {
		kicker: 'Scheduled',
		title: 'Change waiting',
		body: 'The live site stays unchanged until the scheduled go-live time.',
		tone: 'scheduled',
		confetti: false,
	};
};

export const scheduleSentence = ( launch: AdminRecord ): string => {
	const date = firstOf( launch, [ 'startDate', 'startAt' ] );

	if ( ! date ) {
		return 'This scheduled change is not scheduled yet.';
	}

	const time = field( launch, 'startTime' );
	const timezone = field( launch, 'timezone', 'the site timezone' );

	return time
		? `This scheduled change goes live on ${ date } at ${ time } in ${ timezone }.`
		: `This scheduled change goes live on ${ date } in ${ timezone }.`;
};

export const restoreMessage = ( launch: AdminRecord ): string =>
	restoreRelevant( launch )
		? 'You can review previous values before restoring anything.'
		: 'Previous values will be saved before this change goes live, where supported.';

export const safetySentence = ( launch: AdminRecord ): string => {
	if ( hasCompletedRun( launch ) && launchNeedsReview( launch ) ) {
		return 'This result needs review before you retry or restore anything.';
	}

	if ( launchNeedsReview( launch ) ) {
		return 'This change needs review before it can go live.';
	}

	return 'No blocking safety issues are visible for this change.';
};

const itemCountText = ( launch: AdminRecord ): string => {
	const count = numberValue( launch.targetCount );

	if ( count <= 0 ) {
		return 'selected items';
	}

	return `${ count } ${ 1 === count ? 'item' : 'items' }`;
};

const scheduleShortText = ( launch: AdminRecord ): string => {
	const date = firstOf( launch, [ 'startDate', 'startAt' ] );

	if ( ! date ) {
		return 'Not scheduled yet';
	}

	const time = field( launch, 'startTime' );
	const timezone = field( launch, 'timezone', 'site timezone' );

	return time
		? `${ date } at ${ time } (${ timezone })`
		: `${ date } (${ timezone })`;
};

const scheduleHeadlineText = ( launch: AdminRecord ): string => {
	const shortText = scheduleShortText( launch );

	return 'Not scheduled yet' === shortText
		? 'Not scheduled yet'
		: `Scheduled for ${ shortText }`;
};

const lastResultText = ( launch: AdminRecord ): string => {
	const lastRunStatus = field( launch, 'lastRunStatus' );

	return lastRunStatus ? statusLabel( lastRunStatus ) : 'Not started yet';
};

const hasCompletedRun = ( launch: AdminRecord ): boolean =>
	[
		'successful',
		'success',
		'successful_with_warnings',
		'partially_failed',
		'failed',
		'rolled_back',
		'rollback_failed',
	].includes( field( launch, 'lastRunStatus' ).toLowerCase() );

const runNeedsAttention = ( launch: AdminRecord ): boolean =>
	[ 'failed', 'partially_failed', 'rollback_failed' ].includes(
		field( launch, 'lastRunStatus' ).toLowerCase()
	);

export const restoreRelevant = ( launch: AdminRecord ): boolean =>
	[
		'successful',
		'success',
		'partially_failed',
		'failed',
		'rolled_back',
	].includes( field( launch, 'lastRunStatus' ).toLowerCase() );

export const displayDetailValue = (
	value: unknown,
	sensitive: unknown
): string => {
	if ( true === sensitive || '[redacted]' === textValue( value ) ) {
		return 'Hidden for security.';
	}

	return textValue( value, 'Not captured' );
};

export const changeListTitle = ( launch: AdminRecord ): string =>
	hasCompletedRun( launch ) ? 'What changed' : 'Changes waiting to go live';

export const changeListEmpty = ( launch: AdminRecord ): string =>
	hasCompletedRun( launch )
		? 'No saved change details were found for this completed change.'
		: 'No saved changes were found yet. Finish editing the safe copy, then review what will go live.';

export const affectedItemsIntro = ( launch: AdminRecord ): string =>
	hasCompletedRun( launch )
		? 'These are the visible site items this scheduled change touched.'
		: 'These are the visible site items this scheduled change can update.';

export const groupOperations = (
	operations: AdminRecord[]
): { name: string; rows: AdminRecord[] }[] => {
	const groups = new Map< string, AdminRecord[] >();

	for ( const operation of operations ) {
		const group = field( operation, 'group', 'Other changes' );
		groups.set( group, [ ...( groups.get( group ) || [] ), operation ] );
	}

	return Array.from( groups, ( [ name, rows ] ) => ( { name, rows } ) );
};
