import { memo, useEffect, useMemo, useState } from "react";

import { FieldsBehavior, Gallery, Icon, IconAction, Image, ImageDragAndDrop, Modal } from "@ax/components";
import { formatBytes, getFormattedDateWithTimezone } from "@ax/helpers";
import { useModal } from "@ax/hooks";
import type { IImage, ISite } from "@ax/types";

import * as S from "./style";

const ImageField = (props: IImageFieldProps) => {
	const {
		value,
		error,
		onChange,
		selectedContent,
		disabled,
		handleValidation,
		validators,
		site,
		setIsGalleryOpened,
		cropPreview = false,
		fullWidth = false,
		noGallery = false,
		selectPosition = true,
		previewHeight,
		previewWidth,
		objectFit = "cover",
	} = props;

	const isLinkableImage = selectedContent && selectedContent.component === "LinkableImage";
	const hasImage = value && Object.prototype.hasOwnProperty.call(value, "url");
	const isModalOpen = isLinkableImage && !hasImage;
	const { isOpen, toggleModal } = useModal(isModalOpen && !noGallery);
	const { isOpen: isOpenDD, toggleModal: toggleModalDD } = useModal(isModalOpen && noGallery);
	const [previewSrc, setPreviewSrc] = useState<string>();

	const imageUrl = value ? (typeof value === "string" ? value : value.url) : "";
	const imagePosition = value && typeof value === "object" ? value.position : "center";

	useEffect(() => {
		setPreviewSrc(imageUrl);
	}, [imageUrl]);

	const handleDelete = () => {
		if (!disabled) {
			setPreviewSrc("");
			onChange({});
		}
	};

	const getImageSelected = (img: IImage | null | string) => {
		if (img) {
			const url = typeof img === "string" ? img : img.url;
			setPreviewSrc(url);
			onChange(img);
			setIsGalleryOpened?.();
			error && handleValidation && handleValidation(url, validators);
			isOpenDD && toggleModalDD();
		}
	};

	const openImageSelector = () => {
		setIsGalleryOpened?.();
		noGallery ? toggleModalDD() : toggleModal();
	};

	const handleClick = () => {
		if (!disabled) {
			openImageSelector();
		}
	};

	const handleChange = () => {
		if (!disabled) {
			openImageSelector();
		}
	};

	const handlePosition = (newPosition: string) => () => {
		if (value && typeof value === "object") {
			const newValue = { ...value, position: newPosition };
			onChange(newValue);
		}
	};

	const isImage = (object: IImage | null | string): object is IImage => {
		return object !== null && typeof object === "object" && "url" in object;
	};

	const handleAltChange = (altValue: string) => {
		isImage(value) && onChange({ ...value, alt: altValue });
	};

	const handleUpload = (file: IImage[]) => getImageSelected(file[0]);

	const imageElement = useMemo(
		() => <Image url={previewSrc} width={previewWidth ? previewWidth.toString() : "320"} />,
		[previewSrc, previewWidth],
	);

	return (
		<>
			<S.FieldWrapper
				data-testid="fieldWrapper"
				error={error}
				preview={!!previewSrc}
				disabled={disabled}
				onClick={handleClick}
				fullWidth={fullWidth}
			>
				<S.IconWrapper>
					<Icon name="image" size="18" />
				</S.IconWrapper>
				<S.Text>Add image</S.Text>
			</S.FieldWrapper>
			{value && previewSrc && Object.keys(value).length > 1 && typeof value !== "string" && (
				<S.ImageDataWrapper data-testid="imageDataWrapper">
					<S.FileName>{value.name}</S.FileName>
					<S.ImageData>
						Uploaded: {!!value.published && getFormattedDateWithTimezone(value.published, "d MMM Y")}
						<br />
						{`${value.width}x${value.height}px - ${formatBytes(value.size)}`}
					</S.ImageData>
				</S.ImageDataWrapper>
			)}
			<S.Preview
				preview={!!previewSrc}
				data-testid="previewDiv"
				customPreviewHeight={previewHeight}
				customPreviewWidth={previewWidth}
			>
				{previewSrc && (
					<S.ImageContainer objectFit={cropPreview ? "cover" : objectFit} cropPreview={cropPreview}>
						{imageElement}
					</S.ImageContainer>
				)}
				{selectPosition && (
					<S.PositionWrapper>
						<S.PositionTitle>
							<Icon name="grid" size="16" />
							<span>POSITION</span>
						</S.PositionTitle>
						<S.PositionGrid>
							<S.Position onClick={handlePosition("left-top")} active={imagePosition === "left-top"} />
							<S.Position onClick={handlePosition("top")} active={imagePosition === "top"} />
							<S.Position onClick={handlePosition("right-top")} active={imagePosition === "right-top"} />
							<S.Position onClick={handlePosition("left")} active={imagePosition === "left"} />
							<S.Position onClick={handlePosition("center")} active={!imagePosition || imagePosition === "center"} />
							<S.Position onClick={handlePosition("right")} active={imagePosition === "right"} />
							<S.Position onClick={handlePosition("left-bottom")} active={imagePosition === "left-bottom"} />
							<S.Position onClick={handlePosition("bottom")} active={imagePosition === "bottom"} />
							<S.Position onClick={handlePosition("right-bottom")} active={imagePosition === "right-bottom"} />
						</S.PositionGrid>
					</S.PositionWrapper>
				)}
				<S.PreviewActions>
					<IconAction icon="change" onClick={handleChange} />
					<IconAction icon="delete" onClick={handleDelete} />
				</S.PreviewActions>
			</S.Preview>
			{value && isImage(value) && (
				<S.FieldsWrapper>
					<FieldsBehavior
						title="Alternative text"
						name="alt"
						fieldType="TextField"
						value={value.alt || ""}
						onChange={handleAltChange}
					/>
				</S.FieldsWrapper>
			)}
			<Modal isOpen={isOpen} hide={toggleModal} size="XL" title="Select image">
				<Gallery getImageSelected={getImageSelected} toggleModal={toggleModal} site={site} />
			</Modal>
			<Modal isOpen={isOpenDD} hide={toggleModalDD} size="M" title="Upload Media">
				<ImageDragAndDrop
					siteID={site ? site.id : "global"}
					isAllowedToUpload={true}
					handleUpload={handleUpload}
					visible={false}
				/>
			</Modal>
		</>
	);
};

export interface IImageFieldProps {
	value: IImage | null | string;
	error?: boolean;
	onChange: (value: any) => void;
	selectedContent: any;
	disabled?: boolean;
	setIsGalleryOpened?: () => void;
	handleValidation?: (value: string, validators?: Record<string, unknown>) => void;
	validators?: Record<string, unknown>;
	site: ISite;
	cropPreview?: boolean;
	fullWidth?: boolean;
	noGallery?: boolean;
	selectPosition?: boolean;
	previewHeight?: number;
	previewWidth?: number;
	objectFit?: "contain" | "cover";
}

export default memo(ImageField);
