/**
 * JTZL_WebIRC_Chat - Image Message Component
 *
 * @package   JTZL_WebIRC_Chat
 * @copyright Copyright (c) 2025, JT. G.
 * @license   GPL-3.0+
 * @since     3.1.0
 */

import { useState, useRef, useEffect, memo } from 'react';
import type { ImageData } from '../../types/image';
import { useOptimizedImage } from '../../hooks/useOptimizedImage';

interface ImageMessageProps {
	images: ImageData[];
	timestamp: Date;
	sender: string;
	onImageClick: (image: ImageData, index: number) => void;
	formatTimestamp: (date: Date) => string;
	hideHeader?: boolean;
}

interface ImageItemProps {
	image: ImageData;
	index: number;
	onClick: () => void;
	gridClass: string;
}

/**
 * Get grid layout classes based on number of images.
 * Uses responsive classes for better mobile display.
 * Matches the proposal: 2x2 grid for 4 images, 150px each.
 *
 * @since 3.1.0
 */
function getGridLayoutClasses(count: number): string {
	switch (count) {
		case 1:
			return 'grid-cols-1';
		case 2:
			return 'grid-cols-2';
		case 3:
			return 'grid-cols-2';
		case 4:
			return 'grid-cols-2';
		default:
			return 'grid-cols-2';
	}
}

/**
 * Get individual image grid classes based on position and total count.
 * Uses flexible aspect ratios to preserve image dimensions.
 *
 * @since 3.1.0
 */
function getImageGridClasses(index: number, total: number): string {
	// Base classes with flexible aspect ratio.
	const baseClasses = 'w-full';

	// For 3 images: first two side by side, third spans full width.
	if (total === 3 && index === 2) {
		return `${baseClasses} col-span-2`;
	}

	return baseClasses;
}

/**
 * Individual image item with lazy loading and error handling.
 *
 * @since 3.1.0
 */
const ImageItem = memo(
	({ image, index, onClick, gridClass }: ImageItemProps) => {
		const [isInView, setIsInView] = useState(false);
		const imgRef = useRef<HTMLDivElement>(null);

		// Intersection observer for aggressive lazy loading.
		useEffect(() => {
			const observer = new IntersectionObserver(
				(entries) => {
					entries.forEach((entry) => {
						if (entry.isIntersecting) {
							setIsInView(true);
							observer.disconnect();
						}
					});
				},
				{
					rootMargin: '100px', // Increased margin for better mobile performance.
					threshold: 0.01,
				}
			);

			if (imgRef.current) {
				observer.observe(imgRef.current);
			}

			return () => {
				observer.disconnect();
			};
		}, []);

		const imageUrl = image.thumbnailUrl || image.url;

		// Use optimized image loading with caching.
		const { src, isLoading, hasError, isFromCache } = useOptimizedImage(
			isInView ? imageUrl : '',
			undefined
		);

		const handleRetry = (e: React.MouseEvent) => {
			e.stopPropagation();
			// Force reload by toggling isInView.
			setIsInView(false);
			setTimeout(() => setIsInView(true), 0);
		};

		// Calculate aspect ratio from image dimensions.
		const aspectRatio =
			image.width && image.height
				? `${image.width} / ${image.height}`
				: '16 / 9'; // Default to 16:9 if dimensions unknown.

		return (
			<div
				ref={imgRef}
				className={`relative overflow-hidden rounded-md bg-black cursor-pointer hover:opacity-90 active:opacity-75 transition-opacity touch-manipulation ${gridClass}`}
				style={{
					aspectRatio,
					maxHeight: '300px', // Prevent extremely tall images.
				}}
				onClick={onClick}
				role="button"
				tabIndex={0}
				onKeyDown={(e) => {
					if (e.key === 'Enter' || e.key === ' ') {
						e.preventDefault();
						onClick();
					}
				}}
				aria-label={`View image ${index + 1}: ${image.alt}`}
			>
				{/* Loading skeleton with progressive fade */}
				{isLoading && !hasError && (
					<div className="absolute inset-0 bg-muted animate-pulse" />
				)}

				{/* Error state */}
				{hasError && (
					<div className="absolute inset-0 flex flex-col items-center justify-center bg-muted text-muted-foreground p-4">
						<svg
							className="w-8 h-8 mb-2"
							fill="none"
							stroke="currentColor"
							viewBox="0 0 24 24"
							aria-hidden="true"
						>
							<path
								strokeLinecap="round"
								strokeLinejoin="round"
								strokeWidth={2}
								d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
							/>
						</svg>
						<p className="text-xs text-center mb-2">
							Failed to load
						</p>
						<button
							onClick={handleRetry}
							className="text-xs text-primary hover:underline"
							aria-label="Retry loading image"
						>
							Retry
						</button>
					</div>
				)}

				{/* Image with progressive loading effect - uses object-contain to preserve aspect ratio */}
				{src && !hasError && (
					<img
						src={src}
						alt={image.alt}
						className={`w-full h-full object-contain object-center transition-opacity duration-300 ${
							!isLoading ? 'opacity-100' : 'opacity-0'
						}`}
						loading="lazy"
						decoding="async"
					/>
				)}

				{/* Cache indicator (for debugging) */}
				{isFromCache && process.env.NODE_ENV === 'development' && (
					<div className="absolute top-1 right-1 bg-green-500 text-white text-xs px-1 rounded">
						cached
					</div>
				)}
			</div>
		);
	}
);

ImageItem.displayName = 'ImageItem';

/**
 * ImageMessage component for displaying images in chat messages.
 *
 * @since 3.1.0
 */
export const ImageMessage = memo(
	({
		images,
		timestamp,
		sender,
		onImageClick,
		formatTimestamp,
		hideHeader = false,
	}: ImageMessageProps) => {
		const visibleImages = images.slice(0, 4);
		const remainingCount = images.length - 4;
		const gridLayoutClass = getGridLayoutClasses(visibleImages.length);

		// Get avatar initials from sender name.
		const getAvatarInitials = (name: string): string => {
			const cleaned = name.replace(/[@\[\]]/g, '').trim();
			const parts = cleaned.split(/[\s_-]+/);
			if (parts.length >= 2) {
				return (parts[0][0] + parts[1][0]).toUpperCase();
			}
			return cleaned.slice(0, 2).toUpperCase();
		};

		return (
			<div className="group w-full min-w-0">
				{/* Header: Avatar + Sender + Timestamp (conditionally rendered) */}
				{!hideHeader && (
					<div className="flex items-center gap-2 mb-2 min-w-0">
						<div className="inline-flex items-center justify-center rounded-full h-6 w-6 flex-shrink-0 bg-primary text-primary-foreground text-xs">
							{getAvatarInitials(sender)}
						</div>
						<span className="font-medium flex-shrink-0 text-primary">
							{sender}
						</span>
						<span className="text-xs text-muted-foreground ml-auto whitespace-nowrap flex-shrink-0">
							{formatTimestamp(timestamp)}
						</span>
					</div>
				)}

				{/* Image Grid */}
				<div
					className={`grid gap-1 ${gridLayoutClass} ${visibleImages.length > 1 ? 'max-w-[95%] sm:max-w-md' : ''}`}
					role="group"
					aria-label={`${images.length} image${images.length > 1 ? 's' : ''} from ${sender}`}
				>
					{visibleImages.map((image, index) => (
						<ImageItem
							key={image.id}
							image={image}
							index={index}
							onClick={() => onImageClick(image, index)}
							gridClass={getImageGridClasses(
								index,
								visibleImages.length
							)}
						/>
					))}

					{/* Show more indicator for 5+ images */}
					{remainingCount > 0 && (
						<div
							className="relative overflow-hidden rounded-md bg-muted/50 cursor-pointer hover:bg-muted transition-colors flex items-center justify-center w-full"
							style={{
								aspectRatio: '16 / 9',
								maxHeight: '300px',
							}}
							onClick={() => onImageClick(images[4], 4)}
							role="button"
							tabIndex={0}
							onKeyDown={(e) => {
								if (e.key === 'Enter' || e.key === ' ') {
									e.preventDefault();
									onImageClick(images[4], 4);
								}
							}}
							aria-label={`View ${remainingCount} more image${remainingCount > 1 ? 's' : ''}`}
						>
							<span className="text-2xl font-semibold text-muted-foreground">
								+{remainingCount}
							</span>
						</div>
					)}
				</div>
			</div>
		);
	}
);

ImageMessage.displayName = 'ImageMessage';
