/**
 * WordPress dependencies
 */
import { TextareaControl } from '@safe-wordpress/components';
import { useDispatch, useSelect } from '@safe-wordpress/data';
import {
	useCallback,
	useEffect,
	useMemo,
	useRef,
	useState,
} from '@safe-wordpress/element';
import { _x } from '@safe-wordpress/i18n';

/**
 * External dependencies
 */
import clsx from 'clsx';
import { trim } from 'lodash';
import {
	store as NC_DATA,
	useAuthorName,
	withSubscriptionCheck,
} from '@nelio-content/data';
import { DeleteButton } from '@nelio-content/components';
import { dateI18n, getSettings } from '@nelio-content/date';
import { createComment } from '@nelio-content/utils';
import type {
	EditorialComment,
	PostId,
	PostTypeName,
	UserId,
} from '@nelio-content/types';

/**
 * Internal dependencies
 */
import { useIsSaving } from '../../hooks';
import { store as NC_POST_EDITOR } from '../../store';

export const Comments = (): JSX.Element => <InternalComments />;

const InternalComments = withSubscriptionCheck(
	'raw/editorial-comments',
	() => (
		<div className="nelio-content-pqe-extra__comments">
			<CommentList />
			<CommentForm />
		</div>
	)
);

// =======
// HELPERS
// =======

const CommentList = (): JSX.Element | null => {
	const ref = useRef< HTMLUListElement >( null );
	const { comments, newComments } = useComments();
	const deleteComment = useDeleteComment();

	const currentCount = newComments.length;
	const [ count, setCount ] = useState( -1 );
	useEffect( () => {
		if ( count === currentCount ) {
			return;
		}

		if ( count < currentCount ) {
			ref.current?.scrollTo( {
				top: 999_999,
				behavior: count === -1 ? undefined : 'smooth',
			} );
		}

		setCount( currentCount );
	}, [ count, currentCount, setCount ] );

	return (
		<ul ref={ ref } className="nelio-content-pqe-extra__comment-list">
			{ comments.map( ( comment ) => (
				<Comment
					key={ `nelio-content-comment-${ comment.id }` }
					comment={ comment }
				/>
			) ) }
			{ newComments.map( ( comment ) => (
				<Comment
					key={ `nelio-content-comment-${ comment.id }` }
					comment={ comment }
					onDelete={ () => deleteComment( comment.id ) }
				/>
			) ) }
		</ul>
	);
};

const CommentForm = (): JSX.Element => {
	const [ value, setValue ] = useState( '' );
	const isSaving = useIsSaving();
	const addComment = useAddComment();
	return (
		<div className="nelio-content-pqe-extra__comment-form">
			<TextareaControl
				placeholder={ _x(
					'Write a comment and press enter to send…',
					'user',
					'nelio-content'
				) }
				value={ value }
				disabled={ isSaving }
				onChange={ setValue }
				onKeyDown={ ( ev ) => {
					if ( 'Enter' !== ev.key ) {
						return;
					}
					ev.preventDefault();
					addComment( value );
					setValue( '' );
				} }
			/>
		</div>
	);
};

type CommentProps = {
	readonly comment: EditorialComment;
	readonly onDelete?: () => void;
};
const Comment = ( { comment, onDelete }: CommentProps ) => {
	const isSaving = useIsSaving();
	const isCurrentUsers = useIsCurrentUsers( comment?.authorId );
	const authorName = useAuthorName( comment?.authorId );

	return (
		<li
			className={ clsx( 'nelio-content-pqe-extra__comment', {
				'nelio-content-pqe-extra__comment--is-mine': isCurrentUsers,
			} ) }
		>
			<div>
				<div
					className={ clsx( {
						'nelio-content-pqe-extra__comment-bubble': true,
						'nelio-content-pqe-extra__comment-bubble--is-mine':
							isCurrentUsers,
					} ) }
				>
					{ comment?.comment || '' }
				</div>

				{ ! onDelete ? (
					<div
						className={ clsx( {
							'nelio-content-pqe-extra__comment-extra': true,
							'nelio-content-pqe-extra__comment-extra--is-mine':
								isCurrentUsers,
						} ) }
					>
						{ ! isCurrentUsers && (
							<div className="nelio-content-pqe-extra__comment-author">
								{ authorName }
							</div>
						) }
						<div className="nelio-content-pqe-extra__comment-date">
							{ dateI18n(
								getSettings().formats.datetime,
								comment?.date
							) }
						</div>
					</div>
				) : (
					<div className="nelio-content-pqe-extra__comment-actions">
						<span>
							{ isSaving
								? _x( 'Saving…', 'text', 'nelio-content' )
								: _x(
										'New',
										'text (editorial comment)',
										'nelio-content'
								  ) }
						</span>
						{ ' • ' }
						<DeleteButton
							disabled={ isSaving }
							onClick={ onDelete }
						/>
					</div>
				) }
			</div>
		</li>
	);
};

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

const useComments = () => {
	const postId = useSelect( ( s ) => s( NC_POST_EDITOR ).getId(), [] );
	const comments = useSelect(
		( s ) => s( NC_DATA ).getCommentsRelatedToPost( postId ),
		[ postId ]
	);

	const newComments = useSelect(
		( s ) => s( NC_POST_EDITOR ).getNewComments(),
		[]
	);

	return useMemo(
		() => ( { comments, newComments } ),
		[ comments, newComments ]
	);
};

const useDeleteComment = () => {
	const { setNewComments } = useDispatch( NC_POST_EDITOR );
	const newComments = useSelect(
		( select ) => select( NC_POST_EDITOR ).getNewComments(),
		[]
	);

	return useCallback(
		( id: EditorialComment[ 'id' ] ) => {
			void setNewComments( newComments.filter( ( c ) => c.id !== id ) );
		},
		[ setNewComments, newComments ]
	);
};

const useAddComment = () => {
	const { setNewComments } = useDispatch( NC_POST_EDITOR );
	const newComments = useSelect(
		( select ) => select( NC_POST_EDITOR ).getNewComments(),
		[]
	);

	return useCallback(
		( comment: EditorialComment[ 'comment' ] ) => {
			const text = trim( comment );
			if ( ! text ) {
				return;
			}

			void setNewComments( [
				...newComments,
				{
					...createComment( 0 as PostId, 'post' as PostTypeName ),
					comment: text,
				},
			] );
		},
		[ setNewComments, newComments ]
	);
};

const useIsCurrentUsers = ( commentAuthor?: UserId ) =>
	useSelect(
		( select ) => select( NC_DATA ).getCurrentUserId() === commentAuthor,
		[ commentAuthor ]
	);
