/**
 * Video Editor list view — DataViews-powered videos grid.
 *
 * Replaces the bespoke AttachmentPicker / MediaGrid / MediaItem stack with a
 * single `@wordpress/dataviews` grid. Data is fetched server-side (paginated /
 * sorted / filtered / searched by the `godam/v1/video-editor/videos` REST
 * endpoint); the component accumulates pages and appends the next page on
 * demand via a manual "Load more" button (see `loadMore`). DataViews' own
 * search / filter / sort / pagination chrome is hidden (see video-dataview.scss)
 * — a custom toolbar drives the query, mirroring the provided design.
 *
 * @package
 */

/**
 * External dependencies
 */
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';

/**
 * WordPress dependencies
 */
import { __, sprintf } from '@wordpress/i18n';
import { createPortal } from '@wordpress/element';
import {
	Button,
	Dropdown,
	MenuGroup,
	MenuItem,
	NavigableMenu,
	Snackbar,
	Tooltip,
} from '@wordpress/components';
import { DataViews } from '@wordpress/dataviews';
import {
	Icon,
	chevronDown,
	check,
	info,
	moreHorizontal,
	search as searchIcon,
	edit as editIcon,
	video as videoIcon,
	audio as audioIcon,
	copy as copyIcon,
	chartBar as analyticsIcon,
	media as mediaIcon,
} from '@wordpress/icons';

/**
 * Internal dependencies
 */
import { copyGoDAMVideoBlock, prefetchMediaDataForCopy } from '../../utils';
import { notify as notifyGuide, requestWelcome as openGuideWelcome } from '../../onboarding/productGuide';
import { getTourPrioritizeId, subscribeTourPrioritize } from '../../onboarding/tourPrioritize';
import { useGetVideoEditorVideosMutation } from '../../redux/api/video-editor';
import { canManageAttachment } from '../../../../assets/src/js/media-library/utility.js';
import { LayersTabIcon } from '../editor-shell/icons';
import NoThumbnailImage from '../../assets/no-thumbnail.jpg';
import GodamIcon from '../../../../assets/src/images/godam-logo-gradient.svg';
import '@wordpress/dataviews/build-style/style.css';
import './video-dataview.scss';

const PER_PAGE = 20;

/**
 * Media-type options for the primary filter. `key` is sent to the REST endpoint
 * as `media_type`; Videos is the default.
 */
const MEDIA_TYPE_OPTIONS = [
	{ key: 'video', label: __( 'Videos', 'godam' ) },
	{ key: 'image', label: __( 'Images', 'godam' ) },
	{ key: 'audio', label: __( 'Audio', 'godam' ) },
];

/**
 * Secondary filter options, narrowed to those meaningful for the current media
 * type: transcode filters apply to video/audio (images are never transcoded);
 * edited/unedited (authored layers) apply to video/image (audio has no layers).
 * `key` is sent to the REST endpoint as `filter`.
 *
 * @param {string} mediaType video|image|audio.
 * @return {Array} `{ key, label }` options.
 */
const getFilterOptions = ( mediaType ) => {
	const allLabel = {
		video: __( 'All Videos', 'godam' ),
		image: __( 'All Images', 'godam' ),
		audio: __( 'All Audio', 'godam' ),
	}[ mediaType ] || __( 'All', 'godam' );

	const options = [ { key: 'all', label: allLabel } ];

	if ( 'audio' !== mediaType ) {
		options.push(
			{ key: 'edited', label: __( 'Edited', 'godam' ) },
			{ key: 'unedited', label: __( 'Unedited', 'godam' ) },
		);
	}

	if ( 'image' !== mediaType ) {
		options.push(
			{ key: 'transcoded', label: __( 'Transcoded', 'godam' ) },
			{ key: 'non_transcoded', label: __( 'Non Transcoded', 'godam' ) },
		);
	}

	return options;
};

/**
 * "Recently Edited" sort options, mapped to REST `orderby` / `order`.
 */
const SORT_OPTIONS = [
	{ key: 'newest', label: __( 'Newest Uploaded', 'godam' ), orderby: 'date', order: 'desc' },
	{ key: 'oldest', label: __( 'Oldest Uploaded', 'godam' ), orderby: 'date', order: 'asc' },
	{ key: 'recently_edited', label: __( 'Recently Edited', 'godam' ), orderby: 'modified', order: 'desc' },
	{ key: 'name_asc', label: __( 'Name A-Z', 'godam' ), orderby: 'title', order: 'asc' },
	{ key: 'name_desc', label: __( 'Name Z-A', 'godam' ), orderby: 'title', order: 'desc' },
];

/**
 * URL query-param names for the shareable list-view state. Kept distinct from
 * the admin `page` / `id` / `tab` params (owned by App.js) so the filtered view
 * can be bookmarked, shared, and restored on back/forward navigation.
 */
const QUERY_PARAM = {
	mediaType: 'media_type',
	filter: 'filter',
	sort: 'sort',
	search: 'search',
};

const DEFAULT_QUERY = {
	mediaType: 'video',
	filter: 'all',
	sortKey: 'newest',
	search: '',
};

/**
 * Read the shareable list-view query state from the current URL. Unknown or
 * inapplicable values (e.g. a transcode filter under Images, a stale/hand-edited
 * link) fall back to the defaults so the view can't wedge. `filter` is validated
 * against the options for the resolved media type, mirroring handleMediaTypeChange.
 *
 * @return {{mediaType: string, filter: string, sortKey: string, search: string}} Query state.
 */
const readQueryFromUrl = () => {
	const params = new URLSearchParams( window.location.search );

	const rawMediaType = params.get( QUERY_PARAM.mediaType );
	const mediaType = MEDIA_TYPE_OPTIONS.some( ( o ) => o.key === rawMediaType )
		? rawMediaType
		: DEFAULT_QUERY.mediaType;

	const rawFilter = params.get( QUERY_PARAM.filter );
	const filter = getFilterOptions( mediaType ).some( ( o ) => o.key === rawFilter )
		? rawFilter
		: DEFAULT_QUERY.filter;

	const rawSort = params.get( QUERY_PARAM.sort );
	const sortKey = SORT_OPTIONS.some( ( o ) => o.key === rawSort )
		? rawSort
		: DEFAULT_QUERY.sortKey;

	const search = params.get( QUERY_PARAM.search ) || DEFAULT_QUERY.search;

	return { mediaType, filter, sortKey, search };
};

const DEFAULT_VIEW = {
	type: 'grid',
	page: 1,
	perPage: PER_PAGE,
	search: '',
	filters: [],
	sort: {},
	fields: [],
	titleField: 'title',
	mediaField: 'thumbnail',
	descriptionField: 'meta',
	// The whole footer (title + kebab + details) is rendered together inside the
	// `meta` field so it can live in one padded wrapper, so DataViews' own title
	// row is disabled (and hidden in CSS as a safety net).
	showTitle: false,
	showMedia: true,
	showDescription: true,
	layout: {},
};

/**
 * Labelled dropdown used for the filter / sort toolbar controls. Renders a
 * button showing the current selection that opens a single-select menu.
 *
 * @param {Object}   props
 * @param {string}   props.label              Accessible label / aria for the control.
 * @param {Array}    props.options            `{ key, label }` options.
 * @param {string}   props.value              Currently selected option key.
 * @param {Function} props.onChange           Called with the selected option key.
 * @param {string}   [props.toggleTestId]     data-test-id for the toggle button (E2E hook).
 * @param {string}   [props.itemTestIdPrefix] Prefix for each menu item's data-test-id; the option key is appended.
 * @return {JSX.Element} Dropdown control.
 */
const ToolbarDropdown = ( { label, options, value, onChange, toggleTestId, itemTestIdPrefix } ) => {
	const selected = options.find( ( o ) => o.key === value ) || options[ 0 ];

	return (
		<Dropdown
			className="godam-ve-toolbar__dropdown"
			contentClassName="godam-ve-toolbar__dropdown-menu"
			popoverProps={ { placement: 'bottom-end' } }
			renderToggle={ ( { isOpen, onToggle } ) => (
				<Button
					className="godam-ve-toolbar__dropdown-toggle"
					data-test-id={ toggleTestId }
					onClick={ onToggle }
					aria-expanded={ isOpen }
					aria-label={ label }
				>
					<span>{ selected.label }</span>
					<Icon icon={ chevronDown } size={ 20 } />
				</Button>
			) }
			renderContent={ ( { onClose } ) => (
				<NavigableMenu role="menu" orientation="vertical">
					<MenuGroup>
						{ options.map( ( option ) => (
							<MenuItem
								key={ option.key }
								data-test-id={ `${ itemTestIdPrefix }${ option.key }` }
								role="menuitemradio"
								isSelected={ option.key === value }
								icon={ option.key === value ? check : undefined }
								onClick={ () => {
									onChange( option.key );
									onClose();
								} }
							>
								{ option.label }
							</MenuItem>
						) ) }
					</MenuGroup>
				</NavigableMenu>
			) }
		/>
	);
};

/**
 * Per-card "…" actions menu (Preview / Copy / Analytics). Rendered inside the
 * card footer so the whole footer can live in a single wrapper — replaces
 * DataViews' built-in ItemActions kebab.
 *
 * @param {Object}   props
 * @param {Object}   props.item   Video item.
 * @param {Function} props.onCopy Copy-to-clipboard handler.
 * @return {JSX.Element} Dropdown menu.
 */
const CardActionsMenu = ( { item, onCopy } ) => {
	const adminUrl =
		window?.videoData?.adminUrl || window?.pluginInfo?.adminUrl || '/wp-admin/';

	return (
		<Dropdown
			className="godam-ve-card__menu"
			popoverProps={ { placement: 'bottom-end' } }
			renderToggle={ ( { isOpen, onToggle } ) => (
				<Button
					className="godam-ve-card__menu-toggle"
					icon={ moreHorizontal }
					label={ __( 'Quick actions', 'godam' ) }
					aria-expanded={ isOpen }
					onClick={ ( event ) => {
						event.stopPropagation();
						onToggle();
					} }
				/>
			) }
			renderContent={ ( { onClose } ) => (
				<NavigableMenu role="menu" orientation="vertical">
					<MenuGroup>
						<MenuItem
							role="menuitem"
							icon={ videoIcon }
							onClick={ () => {
								window.open( `/?godam_page=video-preview&id=${ item.id }`, '_blank' );
								onClose();
							} }
						>
							{ __( 'Preview', 'godam' ) }
						</MenuItem>
						<MenuItem
							role="menuitem"
							icon={ copyIcon }
							onClick={ () => {
								onCopy( item );
								onClose();
							} }
						>
							{ __( 'Copy block', 'godam' ) }
						</MenuItem>
						{ /* Analytics is a video-only feature (see capability showStats). */ }
						{ 'video' === item.type && (
							<MenuItem
								role="menuitem"
								icon={ analyticsIcon }
								onClick={ () => {
									window.open( `${ adminUrl }admin.php?page=rtgodam_analytics&id=${ item.id }`, '_blank' );
									onClose();
								} }
							>
								{ __( 'View Analytics', 'godam' ) }
							</MenuItem>
						) }
					</MenuGroup>
				</NavigableMenu>
			) }
		/>
	);
};

const VideoEditorDataView = ( { onEdit } ) => {
	const [ getVideos ] = useGetVideoEditorVideosMutation();
	const [ view, setView ] = useState( DEFAULT_VIEW );

	// Query state (drives the REST request, independent of DataViews' hidden
	// built-in controls). Seeded from the URL (lazy initializers run once) so a
	// shared/bookmarked filtered view — and back/forward navigation out of the
	// editor — restores the same list.
	const [ search, setSearch ] = useState( () => readQueryFromUrl().search );
	const [ filter, setFilter ] = useState( () => readQueryFromUrl().filter );
	const [ sortKey, setSortKey ] = useState( () => readQueryFromUrl().sortKey );
	// Primary media-type filter — Videos by default (historic behaviour).
	const [ mediaType, setMediaType ] = useState( () => readQueryFromUrl().mediaType );

	// Attachment id the onboarding tour wants pinned first (the demo video).
	const [ prioritizeId, setPrioritizeId ] = useState( getTourPrioritizeId() );
	useEffect( () => subscribeTourPrioritize( setPrioritizeId ), [] );

	// Accumulated infinite-scroll state.
	const [ items, setItems ] = useState( [] );
	const [ page, setPage ] = useState( 1 );
	const [ hasMore, setHasMore ] = useState( true );
	const [ total, setTotal ] = useState( 0 );
	// Start in the fetching state so the empty placeholder doesn't flash before
	// the first request kicks off on mount.
	const [ fetching, setFetching ] = useState( true );

	// Copy-to-clipboard feedback.
	const [ snackbarMessage, setSnackbarMessage ] = useState( '' );
	const [ showSnackbar, setShowSnackbar ] = useState( false );

	const requestIdRef = useRef( 0 );

	const sortOption = useMemo(
		() => SORT_OPTIONS.find( ( o ) => o.key === sortKey ) || SORT_OPTIONS[ 0 ],
		[ sortKey ],
	);

	// Secondary filter options depend on the selected media type.
	const filterOptions = useMemo( () => getFilterOptions( mediaType ), [ mediaType ] );

	// Reset accumulation whenever the query parameters change.
	const resetCollection = useCallback( () => {
		setItems( [] );
		setPage( 1 );
		setHasMore( true );
	}, [] );

	// A pin change (tour start / end) is a query change like search/filter/sort —
	// reset the collection so page 1 re-fetches with the new prioritize_id and the
	// pinned demo isn't left duplicated in the accumulated list.
	useEffect( () => {
		resetCollection();
	}, [ prioritizeId, resetCollection ] );

	const handleSearchChange = ( event ) => {
		setSearch( event.target.value );
		resetCollection();
	};

	const handleFilterChange = ( key ) => {
		setFilter( key );
		resetCollection();
	};

	const handleSortChange = ( key ) => {
		setSortKey( key );
		resetCollection();
	};

	const handleMediaTypeChange = ( key ) => {
		setMediaType( key );
		// The applicable secondary filters differ per media type, so reset it.
		setFilter( 'all' );
		resetCollection();
	};

	// Mirror the active query into the URL so the filtered list view can be
	// bookmarked/shared and is restored on back/forward navigation (App.js owns
	// the `id` param separately, and preserves these across the list⇄editor
	// switch). replaceState — not push — so filter tweaks and per-keystroke
	// search edits don't flood the browser history; only non-default values are
	// written, keeping the base URL clean.
	useEffect( () => {
		const url = new URL( window.location );
		const sync = ( key, value, defaultValue ) => {
			if ( value && value !== defaultValue ) {
				url.searchParams.set( key, value );
			} else {
				url.searchParams.delete( key );
			}
		};
		sync( QUERY_PARAM.mediaType, mediaType, DEFAULT_QUERY.mediaType );
		sync( QUERY_PARAM.filter, filter, DEFAULT_QUERY.filter );
		sync( QUERY_PARAM.sort, sortKey, DEFAULT_QUERY.sortKey );
		sync( QUERY_PARAM.search, search, DEFAULT_QUERY.search );
		window.history.replaceState( {}, '', url );
	}, [ mediaType, filter, sortKey, search ] );

	// Fetch the current page directly via the REST endpoint. Modelled on the
	// legacy MediaGrid effect: debounce, stale-request guard, append on
	// subsequent pages and replace on page 1.
	useEffect( () => {
		const currentRequestId = ++requestIdRef.current;
		setFetching( true );

		const run = async () => {
			const response = await getVideos( {
				page,
				perPage: PER_PAGE,
				search,
				orderby: sortOption.orderby,
				order: sortOption.order,
				filter,
				mediaType,
				prioritizeId,
			} );

			// Ignore responses for superseded requests.
			if ( requestIdRef.current !== currentRequestId ) {
				return;
			}

			if ( response?.error ) {
				setHasMore( false );
				setFetching( false );
				return;
			}

			const fetched = response?.data?.items || [];
			const totalPages = Number( response?.data?.paginationInfo?.totalPages ) || 0;

			setTotal( Number( response?.data?.paginationInfo?.totalItems ) || 0 );
			// Dedup by id on append: the pinned demo (prioritize_id) can also come
			// back at its natural position on a later page, which would otherwise
			// produce two cards with the same DataViews item id.
			setItems( ( prev ) => {
				if ( page === 1 ) {
					return fetched;
				}
				const seen = new Set( prev.map( ( it ) => it.id ) );
				return [ ...prev, ...fetched.filter( ( it ) => ! seen.has( it.id ) ) ];
			} );

			if ( ( totalPages && page >= totalPages ) || fetched.length === 0 ) {
				setHasMore( false );
			}

			setFetching( false );
		};

		const debounce = setTimeout( run, search ? 400 : 0 );
		return () => clearTimeout( debounce );
	}, [ getVideos, search, filter, mediaType, sortOption.orderby, sortOption.order, page, prioritizeId ] );

	// Load the next page on demand (manual "Load more" button).
	const loadMore = useCallback( () => {
		setPage( ( prev ) => prev + 1 );
	}, [] );

	const handleCopyVideo = useCallback( async ( item ) => {
		const result = await copyGoDAMVideoBlock( item.id );
		setSnackbarMessage(
			result
				? __( 'GoDAM block copied to clipboard', 'godam' )
				: __( 'Failed to copy GoDAM block', 'godam' ),
		);
		setShowSnackbar( true );
	}, [] );

	// Prefetch copy payloads for the currently loaded videos so the Copy action
	// is instant (mirrors the legacy MediaItem behaviour).
	useEffect( () => {
		items.forEach( ( item ) => prefetchMediaDataForCopy( item.id ) );
	}, [ items ] );

	const fields = useMemo(
		() => [
			{
				id: 'thumbnail',
				label: __( 'Thumbnail', 'godam' ),
				enableSorting: false,
				enableHiding: false,
				render: ( { item } ) => {
					const isFallback =
						! item?.thumbnail ||
						item.thumbnail.includes( '.svg' ) ||
						item.thumbnail.includes( 'no-thumbnail' ) ||
						item.thumbnail.includes( 'default' );

					// Audio shows its cover art when it has one; otherwise an audio
					// icon tile stands in for the missing poster.
					const showAudioIcon = 'audio' === item.type && isFallback;

					return (
						<>
							<div
								className="godam-ve-card__media-frame"
								data-test-id={ `godam-video-editor-element-card-${ item.id }` }
							>
								{ showAudioIcon ? (
									<div className="godam-ve-card__thumb godam-ve-card__thumb--audio is-fallback">
										<Icon icon={ audioIcon } size={ 48 } />
									</div>
								) : (
									<img
										src={ isFallback ? NoThumbnailImage : item.thumbnail }
										alt={ item.title || '' }
										className={ `godam-ve-card__thumb ${ isFallback ? 'is-fallback' : '' }` }
									/>
								) }

								{ item.fileLength && (
									<span className="godam-ve-card__duration">{ item.fileLength }</span>
								) }

								{ canManageAttachment( item.author ) && (
									<div className="godam-ve-card__edit-overlay">
										<Button
											variant="primary"
											icon={ editIcon }
											data-test-id={ `godam-video-editor-button-edit-${ item.id }` }
											className="godam-ve-card__edit-button"
											onClick={ ( event ) => {
												event.stopPropagation();
												// Advance the product guide's "open a video" step.
												notifyGuide( 'edit-video' );
												onEdit( item.id );
											} }
										>
											{ __( 'Edit', 'godam' ) }
										</Button>
									</div>
								) }
							</div>

							{ item.godamCentral && (
								<Tooltip text={ __( 'Sourced from GoDAM Central', 'godam' ) }>
									<span className="godam-ve-card__source-badge">
										<img src={ GodamIcon } alt="" aria-hidden="true" />
									</span>
								</Tooltip>
							) }
						</>
					);
				},
			},
			{
				id: 'title',
				label: __( 'Media name', 'godam' ),
				enableGlobalSearch: true,
				getValue: ( { item } ) => item.title || '',
				render: ( { item } ) => (
					<span className="godam-ve-card__title">{ item.title }</span>
				),
			},
			{
				id: 'meta',
				label: __( 'Details', 'godam' ),
				enableSorting: false,
				enableHiding: false,
				getValue: ( { item } ) => item.modifiedFormatted || '',
				render: ( { item } ) => (
					<div className="godam-ve-card__footer">
						<div className="godam-ve-card__title-row">
							<h3 className="godam-ve-card__title">{ item.title }</h3>
							<CardActionsMenu item={ item } onCopy={ handleCopyVideo } />
						</div>
						<span className="godam-ve-card__date">
							{ sprintf(
								/* translators: %s: human-readable date the video was last edited. */
								__( 'Last edited %s', 'godam' ),
								item.modifiedFormatted || '—',
							) }
						</span>
						<div className="godam-ve-card__stats">
							{ /* Audio has no spatial/timeline layers, so omit the count. */ }
							{ 'audio' !== item.type && (
								<span className="godam-ve-card__layers" title={ __( 'Layers', 'godam' ) }>
									<LayersTabIcon />
									{ item.layersCount || 0 }
								</span>
							) }
							{ /* Images are never transcoded — only flag video/audio. */ }
							{ 'image' !== item.type && item.transcodeStatus !== 'transcoded' && (
								<span className="godam-ve-card__badge godam-ve-card__badge--warning">
									<Icon icon={ info } size={ 16 } />
									{ __( 'Non Transcoded', 'godam' ) }
								</span>
							) }
						</div>
					</div>
				),
			},
		],
		[ onEdit, handleCopyVideo ],
	);

	const defaultLayouts = useMemo(
		() => ( {
			grid: {
				layout: {
					primaryField: 'title',
					mediaField: 'thumbnail',
					columnFields: [],
				},
			},
		} ),
		[],
	);

	const paginationInfo = useMemo(
		() => ( { totalItems: total, totalPages: 1 } ),
		[ total ],
	);

	const onChangeView = useCallback( ( next ) => setView( next ), [] );

	const isInitialLoading = fetching && items.length === 0;
	const isEmpty = ! fetching && items.length === 0;

	return (
		<div className="godam-ve-list">
			<div className="godam-ve-list__header">
				<div className="godam-ve-list__heading">
					<h1 className="godam-ve-list__title">{ __( 'Media Editor', 'godam' ) }</h1>
					<p className="godam-ve-list__subtitle">
						{ __( 'Upload media to the WordPress Media Library, GoDAM auto-syncs it here.', 'godam' ) }
					</p>
				</div>
				<Button
					className="godam-ve-list__how-it-works"
					onClick={ () => openGuideWelcome() }
					data-test-id="godam-video-editor-button-how-it-works"
				>
					<Icon icon={ videoIcon } size={ 20 } />
					{ __( 'See how it works', 'godam' ) }
				</Button>
			</div>

			<div className="godam-ve-toolbar" data-test-id="godam-video-editor-toolbar-list">
				<div className="godam-ve-toolbar__search">
					<Icon icon={ searchIcon } size={ 20 } />
					<input
						type="text"
						data-test-id="godam-video-editor-control-search"
						value={ search }
						placeholder={ __( 'Search', 'godam' ) }
						onChange={ handleSearchChange }
						aria-label={ __( 'Search media', 'godam' ) }
					/>
				</div>

				<div className="godam-ve-toolbar__filters">
					<ToolbarDropdown
						label={ __( 'Filter by media type', 'godam' ) }
						options={ MEDIA_TYPE_OPTIONS }
						value={ mediaType }
						onChange={ handleMediaTypeChange }
						toggleTestId="godam-video-editor-button-media-type"
						itemTestIdPrefix="godam-video-editor-control-media-type-"
					/>
					<ToolbarDropdown
						label={ __( 'Filter media', 'godam' ) }
						options={ filterOptions }
						value={ filter }
						onChange={ handleFilterChange }
						toggleTestId="godam-video-editor-button-filter"
						itemTestIdPrefix="godam-video-editor-control-filter-"
					/>
					<ToolbarDropdown
						label={ __( 'Sort media', 'godam' ) }
						options={ SORT_OPTIONS }
						value={ sortKey }
						onChange={ handleSortChange }
						toggleTestId="godam-video-editor-button-sort"
						itemTestIdPrefix="godam-video-editor-control-sort-"
					/>
				</div>
			</div>

			{ isEmpty ? (
				<div className="godam-ve-list__empty" data-test-id="godam-video-editor-content-empty">
					<Icon icon={ mediaIcon } size={ 120 } />
					<h2>{ __( 'You have no media yet!', 'godam' ) }</h2>
					<p>
						{ __( 'Upload media to the', 'godam' ) }{ ' ' }
						<a
							href={ `${ window?.videoData?.adminUrl || '/wp-admin/' }upload.php` }
							target="_blank"
							rel="noopener noreferrer"
						>
							{ __( 'WordPress Media Library', 'godam' ) }
						</a>{ ' ' }
						{ __( 'and GoDAM will sync them here.', 'godam' ) }
					</p>
					{ window?.videoData?.wooActive && (
						<p>{ __( 'You can start selling as soon as you add a product.', 'godam' ) }</p>
					) }
				</div>
			) : (
				<DataViews
					data-test-id="godam-video-editor-content-list"
					data={ items }
					fields={ fields }
					view={ view }
					onChangeView={ onChangeView }
					defaultLayouts={ defaultLayouts }
					paginationInfo={ paginationInfo }
					getItemId={ ( item ) => String( item.id ) }
					isLoading={ isInitialLoading }
					search={ false }
					onClickItem={ ( item ) => {
						if ( canManageAttachment( item.author ) ) {
							notifyGuide( 'edit-video' );
							onEdit( item.id );
						}
					} }
					isItemClickable={ ( item ) => canManageAttachment( item.author ) }
				/>
			) }

			{ /* "Showing X of Y" count + manual Load more button. */ }
			{ items.length > 0 && (
				<div className="godam-ve-list__loadmore">
					<p className="godam-ve-list__count" data-test-id="godam-video-editor-element-count">
						{ sprintf(
							/* translators: 1: number of loaded media items, 2: total media items. */
							__( 'Showing %1$d of %2$d media items', 'godam' ),
							items.length,
							total,
						) }
					</p>
					{ hasMore && (
						<Button
							variant="secondary"
							data-test-id="godam-video-editor-button-load-more"
							className="godam-ve-list__loadmore-button"
							onClick={ loadMore }
							isBusy={ fetching }
							disabled={ fetching }
						>
							{ __( 'Load more', 'godam' ) }
						</Button>
					) }
				</div>
			) }

			{ showSnackbar &&
				createPortal(
					<Snackbar
						className="godam-ve-snackbar"
						onRemove={ () => setShowSnackbar( false ) }
					>
						{ snackbarMessage }
					</Snackbar>,
					document.body,
				) }
		</div>
	);
};

export default VideoEditorDataView;
