import { devlog } from "@frontend/kitui";
import { CropIcon } from "@icons/CropIcon";
import { ResetIcon } from "@icons/ResetIcon";
import {
    Box,
    Button,
    IconButton,
    Modal,
    Slider,
    SxProps,
    Theme,
    Typography,
    useMediaQuery,
    useTheme,
} from "@mui/material";
import { enqueueSnackbar } from "notistack";
import { FC, useEffect, useMemo, useRef, useState } from "react";
import ReactCrop, { PercentCrop, PixelCrop } from "react-image-crop";
import "react-image-crop/dist/ReactCrop.css";
import { getCroppedImageBlob, getDarkenedAndResizedImageBlob, getRotatedImageBlob } from "./utils/imageManipulation";


const styleSlider: SxProps<Theme> = {
    color: "#7E2AEA",
    height: "12px",
    "& .MuiSlider-track": {
        border: "none",
    },
    "& .MuiSlider-rail": {
        backgroundColor: "#F2F3F7",
        border: `1px solid #9A9AAF`,
    },
    "& .MuiSlider-thumb": {
        height: 26,
        width: 26,
        border: `6px solid #7E2AEA`,
        backgroundColor: "white",
        boxShadow: `0px 0px 0px 3px white,
                0px 4px 4px 3px #C3C8DD`,
        "&:focus, &:hover, &.Mui-active, &.Mui-focusVisible": {
            boxShadow: `0px 0px 0px 3px white,
                    0px 4px 4px 3px #C3C8DD`,
    },
  },
};

interface Props {
    isOpen: boolean;
    imageBlob: Blob | null;
    originalImageUrl: string | null;
    setCropModalImageBlob: (imageBlob: Blob) => void;
    onClose: () => void;
    onSaveImageClick: (imageBlob: Blob) => void;
}

export const CropModal: FC<Props> = ({ isOpen, imageBlob, originalImageUrl, setCropModalImageBlob, onSaveImageClick, onClose }) => {
    const theme = useTheme();
    const [percentCrop, setPercentCrop] = useState<PercentCrop>();
    const [completedCrop, setCompletedCrop] = useState<PixelCrop>();
    const [darken, setDarken] = useState(0);
    const [scale, setScale] = useState<number>(1);
    const [imageWidth, setImageWidth] = useState<number | null>(null);
    const [imageHeight, setImageHeight] = useState<number | null>(null);
    const cropImageElementRef = useRef<HTMLImageElement>(null);
    const isMobile = useMediaQuery(theme.breakpoints.down(786));

    const imageUrl = useMemo(() => imageBlob && URL.createObjectURL(imageBlob), [imageBlob]);

    function resetEditState() {
        setPercentCrop(undefined);
        setCompletedCrop(undefined);
        setDarken(0);
        setScale(1);
    }

    async function handleCropClick() {
        if (!cropImageElementRef.current) throw new Error("No image");
        if (!completedCrop) return;

        try {
            const blob = await getCroppedImageBlob(cropImageElementRef.current, completedCrop);

            setCropModalImageBlob(blob);
            setPercentCrop(undefined);
            setCompletedCrop(undefined);
        } catch (error) {
            devlog("getCroppedImageBlob error", error);
            enqueueSnackbar("Не удалось изменить изображение");
        }
    };

    async function handleRotateClick() {
        if (!cropImageElementRef.current) throw new Error("No image");

        try {
            const blob = await getRotatedImageBlob(cropImageElementRef.current);

            setCropModalImageBlob(blob);
            setPercentCrop(undefined);
            setCompletedCrop(undefined);
        } catch (error) {
            devlog("getRotatedImageBlob error", error);
            enqueueSnackbar("Не удалось изменить изображение");
        }
    }

    async function handleSaveClick() {
        if (!cropImageElementRef.current) throw new Error("No image");

        try {
            const blob = await getDarkenedAndResizedImageBlob(cropImageElementRef.current, scale, darken / 100);
            onSaveImageClick?.(blob);
            resetEditState();
            onClose();
        } catch (error) {
            devlog("getDarkenedImageBlob error", error);
            enqueueSnackbar("Не удалось сохранить изображение");
        }
    }

    async function handleLoadOriginalImage() {
        if (!originalImageUrl) return;

        const response = await fetch(originalImageUrl);
        const blob = await response.blob();

        setCropModalImageBlob(blob);
        resetEditState();
    }

    return (
        <Modal
            open={isOpen}
            onClose={() => {
                resetEditState();
                onClose();
            }}
            aria-labelledby="modal-modal-title"
            aria-describedby="modal-modal-description"
        >
            <Box sx={{
                position: "absolute",
                top: "50%",
                left: "50%",
                transform: "translate(-50%, -50%)",
                bgcolor: "background.paper",
                boxShadow: 24,
                padding: "20px",
                borderRadius: "8px",
                width: isMobile ? "343px" : "620px",
            }}>
                <Box sx={{
                    height: "320px",
                    backgroundSize: "cover",
                    backgroundRepeat: "no-repeat",
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "center",
                }}>
                    {imageUrl && (
                        <ReactCrop
                            crop={percentCrop}
                            onChange={(_, percentCrop) => setPercentCrop(percentCrop)}
                            onComplete={(c) => setCompletedCrop(c)}
                            minWidth={50}
                            minHeight={50}
                        >
                            <img
                                onLoad={e => {
                                    setImageWidth(e.currentTarget.naturalWidth);
                                    setImageHeight(e.currentTarget.naturalHeight);
                                }}
                                ref={cropImageElementRef}
                                alt="Crop me"
                                src={imageUrl}
                                style={{
                                    filter: `brightness(${100 - darken}%)`,
                                    width: imageWidth ? imageWidth * scale : undefined,
                                    height: "100%",
                                    maxWidth: "100%",
                                    maxHeight: "320px",
                                    display: "block",
                                    objectFit: "contain",
                                }}
                            />
                        </ReactCrop>
                    )}
                </Box>
                <Box sx={{
                    color: "#7E2AEA",
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "center",
                    fontSize: "16px",
                    fontWeight: "600",
                    my: "20px",
                }}>
                    {imageWidth && imageHeight && ((percentCrop?.height && percentCrop?.width)
                        ? <Typography sx={{ color: "#7E2AEA" }}>
                            {`${Math.round(percentCrop.width / 100 * imageWidth * scale)} x ${Math.round(percentCrop.height / 100 * imageHeight * scale)} px`}
                        </Typography>
                        : <Typography sx={{ color: "#7E2AEA" }}>
                            {`${Math.round(imageWidth * scale)} x ${Math.round(imageHeight * scale)} px`}
                        </Typography>
                    )}
                </Box>
                <Box sx={{
                    display: isMobile ? "block" : "flex",
                    alignItems: "end",
                    justifyContent: "space-between",
                }}>
                    <IconButton onClick={handleRotateClick}>
                        <ResetIcon />
                    </IconButton>
                    <Box>
                        <Typography sx={{ color: "#9A9AAF", fontSize: "16px" }}>
                            Размер
                        </Typography>
                        <Slider
                            sx={[styleSlider, {
                                width: isMobile ? "350px" : "250px",
                            }]}
                            value={scale * 100}
                            min={1}
                            max={200}
                            step={1}
                            onChange={(_, newValue) => {
                                setScale((newValue as number) * 0.01);
                            }}
                        />
                    </Box>
                    <Box>
                        <Typography sx={{ color: "#9A9AAF", fontSize: "16px" }}>
                            Затемнение
                        </Typography>
                        <Slider
                            sx={[styleSlider, {
                                width: isMobile ? "350px" : "250px",
                            }]}
                            value={darken}
                            min={0}
                            max={100}
                            step={1}
                            onChange={(_, newValue) => setDarken(newValue as number)}
                        />
                    </Box>
                </Box>
                <Box sx={{
                    marginTop: "40px",
                    width: "100%",
                    display: "flex",
                }}>
                    <Button
                        onClick={handleSaveClick}
                        disableRipple
                        data-cy="crop-modal-save-button"
                        sx={{
                            height: "48px",
                            color: "#7E2AEA",
                            borderRadius: "8px",
                            border: "1px solid #7E2AEA",
                            marginRight: "10px",
                            px: "20px",
                        }}
                    >Сохранить</Button>
                    <Button
                        onClick={handleLoadOriginalImage}
                        disableRipple
                        disabled={!originalImageUrl}
                        sx={{
                            width: "215px",
                            height: "48px",
                            color: "#7E2AEA",
                            borderRadius: "8px",
                            border: "1px solid #7E2AEA",
                            marginRight: "10px",
                            ml: "auto",
                        }}
                    >
                        Загрузить оригинал
                    </Button>
                    <Button
                        onClick={handleCropClick}
                        disableRipple
                        variant="contained"
                        disabled={!completedCrop?.width || !completedCrop?.height}
                        sx={{
                            padding: "10px 20px",
                            borderRadius: "8px",
                            background: theme.palette.brightPurple.main,
                            fontSize: "18px",
                        }}
                    >
                        <CropIcon />
                        Обрезать
                    </Button>
                </Box>
            </Box>
        </Modal>
    );
};

export function useCropModalState(initialOpenState = false) {
    const [isCropModalOpen, setOpened] = useState(initialOpenState);
    const [imageBlob, setCropModalImageBlob] = useState<Blob | null>(null);
    const [originalImageUrl, setOriginalImageUrl] = useState<string | null>(null);

    const closeCropModal = () => {
        setOpened(false);
        setCropModalImageBlob(null);
        setOriginalImageUrl(null);
    };

    async function openCropModal(image: Blob | string, originalImageUrl: string | null | undefined = null) {
        if (typeof image === "string") {
            const response = await fetch(image);
            image = await response.blob();
        }

        setCropModalImageBlob(image);
        setOriginalImageUrl(originalImageUrl);
        setOpened(true);
    }

    return {
        isCropModalOpen,
        openCropModal,
        closeCropModal,
        imageBlob,
        setCropModalImageBlob,
        originalImageUrl,
    } as const;
}
