/**
 * WordPress dependencies
 */
import { Button, CheckboxControl, Dashicon } from '@safe-wordpress/components';
import { useSelect, useDispatch } from '@safe-wordpress/data';
import { _x } from '@safe-wordpress/i18n';

/**
 * External dependencies
 */
import clsx from 'clsx';
import { DeleteButton } from '@nelio-content/components';
import { useAuthorName, store as NC_DATA } from '@nelio-content/data';
import { store as NC_TASK_EDITOR } from '@nelio-content/task-editor';
import { getTaskDateDue, getHumanDateDue } from '@nelio-content/utils';
import type { EditorialTask, Maybe, Uuid } from '@nelio-content/types';

/**
 * Internal dependencies
 */
import './style.scss';
import { store as NC_EDIT_POST } from '../../../store';
import { useMemo } from '@safe-wordpress/element';

export type TaskProps = {
	readonly taskId: Uuid;
};

export const Task = ( { taskId }: TaskProps ): JSX.Element => {
	const task = useTask( taskId );
	const { canCompleteTask, canDeleteTask, canEditTask } =
		usePermissions( taskId );
	const { isDeleting, isSynching, isPastDateDue } = useStatus( taskId );

	const { completed, color = '', task: description } = task || {};

	const editTask = useTaskEditor( task );
	const deleteTask = useTaskDeleter( taskId );
	const toggleTaskCompletion = useTaskToggler( taskId );

	const assignee = useAuthorName(
		task?.assigneeId,
		_x( 'Unknown Assignee', 'text', 'nelio-content' )
	);
	const post = useSelect(
		( select ) => select( NC_EDIT_POST ).getPost(),
		[]
	);
	const humanDateDue = task
		? getHumanDateDue( post, task.dateType, task.dateValue )
		: '';

	return (
		<div
			className={ clsx( {
				'nelio-content-editorial-task': true,
				[ `nelio-content-editorial-task--is-${ color }` ]: !! color,
				[ `nelio-content-editorial-task--is-task-${ taskId }` ]: true,
				'nelio-content-editorial-task--is-due': isPastDateDue,
			} ) }
		>
			<CheckboxControl
				className={ clsx( {
					'nelio-content-editorial-task__control': true,
					'nelio-content-editorial-task__control--is-completed':
						completed,
				} ) }
				label={ description }
				onChange={ toggleTaskCompletion }
				checked={ completed }
				disabled={ ! canCompleteTask || isDeleting || isSynching }
			/>
			<div
				className={ clsx( {
					'nelio-content-editorial-task__extra': true,
					'nelio-content-editorial-task__extra--is-completed':
						completed,
					'nelio-content-editorial-task__extra--is-deleting':
						isDeleting,
					'nelio-content-editorial-task__extra--is-due':
						isPastDateDue,
					'nelio-content-editorial-task__extra--is-synching':
						isSynching,
				} ) }
			>
				{ isSynching && _x( 'Saving…', 'text', 'nelio-content' ) }
				{ ! isSynching && `${ assignee } • ${ humanDateDue }` }
				{ isPastDateDue && <Dashicon icon="warning" /> }
			</div>

			<div
				className={ clsx( {
					'nelio-content-editorial-task__actions': true,
					'nelio-content-editorial-task__actions--is-deleting':
						isDeleting,
					'nelio-content-editorial-task__actions--is-synching':
						isSynching,
				} ) }
			>
				<Button
					variant="link"
					disabled={ ! canEditTask || isDeleting || isSynching }
					onClick={ editTask }
				>
					{ _x( 'Edit', 'command', 'nelio-content' ) }
				</Button>
				<DeleteButton
					disabled={ ! canDeleteTask || isSynching }
					isDeleting={ isDeleting }
					onClick={ deleteTask }
				/>
			</div>
		</div>
	);
};

// =====
// HOOKS
// =====

const useTask = ( taskId: Uuid ) =>
	useSelect( ( select ) => select( NC_DATA ).getTask( taskId ), [ taskId ] );

const usePermissions = ( taskId: Uuid ) => {
	const task = useTask( taskId );
	return useSelect(
		( select ) => {
			const canEditTask =
				select( NC_DATA ).canCurrentUserEditTask( task );
			const canDeleteTask =
				select( NC_DATA ).canCurrentUserDeleteTask( task );

			return {
				canCompleteTask: !! task && canEditTask,
				canDeleteTask: !! task && canDeleteTask,
				canEditTask: !! task && canEditTask,
			};
		},
		[ task ]
	);
};

const EMPTY = {
	isDeleting: false,
	isSynching: false,
	isPastDateDue: false,
} as const;

const useStatus = ( taskId: Uuid ) => {
	const task = useTask( taskId );

	const sel = useSelect(
		( select ) => {
			const isDeleting =
				select( NC_EDIT_POST ).isEditorialTaskBeingDeleted( taskId );
			const isSynching =
				select( NC_EDIT_POST ).isEditorialTaskBeingSynched( taskId );
			const postDate = select( NC_EDIT_POST ).getPost()?.date;
			const today = select( NC_DATA ).getToday();
			return { isDeleting, isSynching, postDate, today };
		},
		[ taskId ]
	);

	return useMemo( () => {
		if ( ! task ) {
			return EMPTY;
		}

		const isPastDateDue =
			! task.completed &&
			! sel.isSynching &&
			getTaskDateDue( {
				baseDatetime: sel.postDate || undefined,
				dateType: task.dateType,
				dateValue: task.dateValue,
			} ) < sel.today;

		return {
			isDeleting: sel.isDeleting,
			isSynching: sel.isSynching,
			isPastDateDue,
		};
	}, [ task, sel.isDeleting, sel.isSynching, sel.postDate, sel.today ] );
};

const useTaskEditor = ( task: Maybe< EditorialTask > ) => {
	const post = useSelect(
		( select ) => select( NC_EDIT_POST ).getPost(),
		[]
	);
	const { openExistingTaskEditor } = useDispatch( NC_TASK_EDITOR );
	return () =>
		!! post &&
		!! task &&
		openExistingTaskEditor( task, {
			context: 'post',
			post,
		} );
};

const useTaskDeleter = ( taskId: Uuid ) => {
	const { deleteEditorialTask } = useDispatch( NC_EDIT_POST );
	return () => deleteEditorialTask( taskId );
};

const useTaskToggler = ( taskId: Uuid ) => {
	const task = useTask( taskId );
	const { markTaskAsCompleted } = useDispatch( NC_EDIT_POST );
	return () => markTaskAsCompleted( taskId, ! task?.completed );
};
