import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
  Alert,
  Box,
  Button,
  Grid,
  Stack,
  Typography,
} from '@mui/material';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import { useNavigate } from 'react-router-dom';
import { useAppStore } from '../store/useAppStore';
import { cropSingleImage } from '../utils/cropUtils';

const MIN_SELECTION = 5;
const DEFAULT_SELECTION = { top: 10, left: 10, width: 80, height: 80 };

const clamp = (value, min, max) => Math.min(Math.max(value, min), max);

const selectionFromConfig = (config) => {
  if (!config?.imageWidth || !config?.imageHeight) return DEFAULT_SELECTION;
  const fallback = {
    left: (config.cropAreaX / config.imageWidth) * 100,
    top: (config.cropAreaY / config.imageHeight) * 100,
    width: (config.width / config.imageWidth) * 100,
    height: (config.height / config.imageHeight) * 100,
  };
  return {
    top: config.selection?.top ?? fallback.top,
    left: config.selection?.left ?? fallback.left,
    width: config.selection?.width ?? fallback.width,
    height: config.selection?.height ?? fallback.height,
  };
};

const CropStep = () => {
  const navigate = useNavigate();
  const uploadedImages = useAppStore((state) => state.uploadedImages);
  const cropConfig = useAppStore((state) => state.cropConfig);
  const coverImageId = useAppStore((state) => state.coverImageId);
  const coverCropConfig = useAppStore((state) => state.coverCropConfig);
  const updateCropConfig = useAppStore((state) => state.updateCropConfig);
  const updateCoverCropConfig = useAppStore((state) => state.updateCoverCropConfig);
  const setCroppedCoverImage = useAppStore((state) => state.setCroppedCoverImage);
  const resetFromStep = useAppStore((state) => state.resetFromStep);
  const setError = useAppStore((state) => state.setError);
  const nonCoverImages = useMemo(
    () => uploadedImages.filter((img) => img.id !== coverImageId),
    [coverImageId, uploadedImages],
  );
  const [selectedImageId, setSelectedImageId] = useState(() => {
    if (cropConfig?.referenceImageId) return cropConfig.referenceImageId;
    const firstNonCover = nonCoverImages[0];
    return firstNonCover?.id || uploadedImages[0]?.id || null;
  });
  const [imageSize, setImageSize] = useState({
    width: cropConfig?.imageWidth || 0,
    height: cropConfig?.imageHeight || 0,
  });
  const [selection, setSelection] = useState(
    cropConfig?.selection ? cropConfig.selection : DEFAULT_SELECTION,
  );
  const [saved, setSaved] = useState(false);
  const [savingCover, setSavingCover] = useState(false);
  const containerRef = useRef(null);
  const dragInfoRef = useRef(null);
  const hasGeneralTargets = nonCoverImages.length > 0;
  const canProceed = hasGeneralTargets ? Boolean(cropConfig?.imageWidth) : true;
  const isCoverSelected = selectedImageId && selectedImageId === coverImageId;
  const activeConfig = isCoverSelected ? coverCropConfig : cropConfig;

  const selectedImage = useMemo(
    () => uploadedImages.find((img) => img.id === selectedImageId),
    [selectedImageId, uploadedImages],
  );

  useEffect(() => {
    if (!uploadedImages.length) return;
    if (!selectedImage) {
      const fallback =
        nonCoverImages[0] || uploadedImages[0];
      if (fallback) {
        setSelectedImageId(fallback.id);
      }
    }
  }, [nonCoverImages, selectedImage, uploadedImages]);

  useEffect(() => {
    if (!selectedImage) return;
    const img = new Image();
    img.onload = () => {
      setImageSize({ width: img.width, height: img.height });
    };
    img.src = selectedImage.previewUrl;
  }, [selectedImage]);

  useEffect(() => {
    if (
      activeConfig?.referenceImageId === selectedImageId &&
      activeConfig?.imageWidth
    ) {
      setSelection(selectionFromConfig(activeConfig));
      setSaved(true);
    } else {
      setSelection(DEFAULT_SELECTION);
      setSaved(false);
    }
  }, [activeConfig, selectedImageId]);

  const applyMove = (base, deltaX, deltaY) => {
    const maxLeft = 100 - base.width;
    const maxTop = 100 - base.height;
    return {
      ...base,
      left: clamp(base.left + deltaX, 0, maxLeft),
      top: clamp(base.top + deltaY, 0, maxTop),
    };
  };

  const applyNorth = (base, deltaY) => {
    const limit = base.top + base.height - MIN_SELECTION;
    const newTop = clamp(base.top + deltaY, 0, limit);
    const newHeight = clamp(base.height + (base.top - newTop), MIN_SELECTION, 100 - newTop);
    return { ...base, top: newTop, height: newHeight };
  };

  const applySouth = (base, deltaY) => {
    const newHeight = clamp(
      base.height + deltaY,
      MIN_SELECTION,
      100 - base.top,
    );
    return { ...base, height: newHeight };
  };

  const applyWest = (base, deltaX) => {
    const limit = base.left + base.width - MIN_SELECTION;
    const newLeft = clamp(base.left + deltaX, 0, limit);
    const newWidth = clamp(
      base.width + (base.left - newLeft),
      MIN_SELECTION,
      100 - newLeft,
    );
    return { ...base, left: newLeft, width: newWidth };
  };

  const applyEast = (base, deltaX) => {
    const newWidth = clamp(
      base.width + deltaX,
      MIN_SELECTION,
      100 - base.left,
    );
    return { ...base, width: newWidth };
  };

  const resizeSelection = (base, type, deltaX, deltaY) => {
    let draft = { ...base };
    if (type.includes('n')) {
      draft = applyNorth(draft, deltaY);
    }
    if (type.includes('s')) {
      draft = applySouth(draft, deltaY);
    }
    if (type.includes('w')) {
      draft = applyWest(draft, deltaX);
    }
    if (type.includes('e')) {
      draft = applyEast(draft, deltaX);
    }
    return draft;
  };

  const handlePointerMove = useCallback(
    (event) => {
      const dragInfo = dragInfoRef.current;
      if (!dragInfo || !containerRef.current) return;
      const bounds = containerRef.current.getBoundingClientRect();
      if (!bounds.width || !bounds.height) return;
      const deltaX = ((event.clientX - dragInfo.startX) / bounds.width) * 100;
      const deltaY = ((event.clientY - dragInfo.startY) / bounds.height) * 100;
      let nextSelection = dragInfo.selection;
      if (dragInfo.type === 'move') {
        nextSelection = applyMove(dragInfo.selection, deltaX, deltaY);
      } else {
        nextSelection = resizeSelection(dragInfo.selection, dragInfo.type, deltaX, deltaY);
      }
      setSelection(nextSelection);
      setSaved(false);
    },
    [],
  );

  const stopDragging = useCallback(() => {
    dragInfoRef.current = null;
    window.removeEventListener('pointermove', handlePointerMove);
    window.removeEventListener('pointerup', stopDragging);
  }, [handlePointerMove]);

  const startDrag = (type) => (event) => {
    event.preventDefault();
    event.stopPropagation();
    if (!containerRef.current) return;
    dragInfoRef.current = {
      type,
      startX: event.clientX,
      startY: event.clientY,
      selection,
    };
    window.addEventListener('pointermove', handlePointerMove);
    window.addEventListener('pointerup', stopDragging);
  };

  useEffect(
    () => () => {
      stopDragging();
    },
    [stopDragging],
  );

  const currentCropArea = useMemo(() => {
    if (!imageSize.width || !imageSize.height) return null;
    return {
      width: (selection.width / 100) * imageSize.width,
      height: (selection.height / 100) * imageSize.height,
      x: (selection.left / 100) * imageSize.width,
      y: (selection.top / 100) * imageSize.height,
    };
  }, [imageSize.height, imageSize.width, selection]);

  const handleSaveCrop = async () => {
    if (!currentCropArea || !selectedImage) return;
    const config = {
      x: 0,
      y: 0,
      zoom: 1,
      width: currentCropArea.width,
      height: currentCropArea.height,
      top: 0,
      bottom: 0,
      left: 0,
      right: 0,
      cropAreaX: currentCropArea.x,
      cropAreaY: currentCropArea.y,
      imageWidth: imageSize.width,
      imageHeight: imageSize.height,
      referenceImageId: selectedImage.id,
      selection,
    };
    if (isCoverSelected) {
      setSavingCover(true);
      try {
        updateCoverCropConfig(config);
        const croppedCover = await cropSingleImage(selectedImage, config);
        setCroppedCoverImage(croppedCover);
        resetFromStep('epub');
        setSaved(true);
      } catch (error) {
        setError(error.message);
      } finally {
        setSavingCover(false);
      }
      return;
    }
    updateCropConfig(config);
    resetFromStep('crop');
    setSaved(true);
  };

  if (!uploadedImages.length) {
    return (
      <Stack spacing={2}>
        <Alert severity="info">Önce görsel yüklemelisin.</Alert>
        <Button variant="contained" onClick={() => navigate('/')}>
          Yüklemeye dön
        </Button>
      </Stack>
    );
  }

  const handleConfigs = [
    { key: 'n', type: 'n', style: { top: -6, left: '50%', transform: 'translate(-50%, -50%)', cursor: 'ns-resize' } },
    { key: 's', type: 's', style: { bottom: -6, left: '50%', transform: 'translate(-50%, 50%)', cursor: 'ns-resize' } },
    { key: 'w', type: 'w', style: { left: -6, top: '50%', transform: 'translate(-50%, -50%)', cursor: 'ew-resize' } },
    { key: 'e', type: 'e', style: { right: -6, top: '50%', transform: 'translate(50%, -50%)', cursor: 'ew-resize' } },
    { key: 'nw', type: 'nw', style: { top: -6, left: -6, cursor: 'nwse-resize' } },
    { key: 'ne', type: 'ne', style: { top: -6, right: -6, cursor: 'nesw-resize' } },
    { key: 'sw', type: 'sw', style: { bottom: -6, left: -6, cursor: 'nesw-resize' } },
    { key: 'se', type: 'se', style: { bottom: -6, right: -6, cursor: 'nwse-resize' } },
  ];

  return (
    <Stack spacing={4}>
      <Typography variant="h6">Referans görseli seç</Typography>
      <Grid container spacing={2}>
        {uploadedImages.map((image) => (
          <Grid item xs={6} sm={4} md={3} key={image.id}>
            <Box
              sx={{
                border:
                  image.id === selectedImageId
                    ? '3px solid #000'
                    : '2px solid rgba(0,0,0,0.1)',
                borderRadius: 2,
                overflow: 'hidden',
                cursor: 'pointer',
                position: 'relative',
              }}
              onClick={() => {
                setSelectedImageId(image.id);
                setSaved(false);
                if (image.id !== coverImageId) {
                  resetFromStep('crop');
                }
              }}
            >
              <img
                src={image.previewUrl}
                alt={image.filename}
                style={{ width: '100%', display: 'block' }}
              />
              {image.id === coverImageId && (
                <Box
                  sx={{
                    position: 'absolute',
                    top: 8,
                    right: 8,
                    px: 1.5,
                    py: 0.5,
                    borderRadius: 999,
                    bgcolor: 'secondary.main',
                    color: '#fff',
                    fontSize: '0.75rem',
                    fontWeight: 600,
                  }}
                >
                  Kapak
                </Box>
              )}
            </Box>
          </Grid>
        ))}
      </Grid>

      {isCoverSelected ? (
        <Alert severity="info">
          Kapak görseli için ayrı bir crop ayarı oluşturuyorsun. Bu ayar OCR sırasını etkilemez.
        </Alert>
      ) : (
        <Alert severity="info">
          Seçtiğin referans, kapak dışındaki tüm görsellere uygulanacak.
        </Alert>
      )}

      {selectedImage && (
        <Box sx={{ width: '100%', overflow: 'hidden', borderRadius: 2, backgroundColor: '#0000000a' }}>
          <Box
            ref={containerRef}
            sx={{
              position: 'relative',
              width: '100%',
              maxWidth: 410,
              mx: 'auto',
            }}
          >
            <img
              src={selectedImage.previewUrl}
              alt={selectedImage.filename}
              style={{ width: '100%', display: 'block', userSelect: 'none', pointerEvents: 'none' }}
            />
            <Box
              sx={{
                position: 'absolute',
                inset: 0,
                pointerEvents: 'none',
              }}
            >
              <Box
                role="presentation"
                onPointerDown={startDrag('move')}
                sx={{
                  position: 'absolute',
                  top: `${selection.top}%`,
                  left: `${selection.left}%`,
                  width: `${selection.width}%`,
                  height: `${selection.height}%`,
                  border: '3px solid #000',
                  boxShadow: '0 0 0 9999px rgba(0,0,0,0.45)',
                  cursor: 'move',
                  pointerEvents: 'auto',
                }}
              >
                {handleConfigs.map((handle) => (
                  <Box
                    key={handle.key}
                    role="presentation"
                    onPointerDown={startDrag(handle.type)}
                    sx={{
                      position: 'absolute',
                      width: 14,
                      height: 14,
                      borderRadius: '50%',
                      backgroundColor: '#000',
                      border: '2px solid #fff',
                      ...handle.style,
                      pointerEvents: 'auto',
                    }}
                  />
                ))}
              </Box>
            </Box>
          </Box>
        </Box>
      )}

      {saved && (
        <Stack direction="row" spacing={1} alignItems="center" color="success.main">
          <CheckCircleIcon color="success" />
          <Typography>
            {isCoverSelected ? 'Kapak crop ayarı kaydedildi.' : 'Crop ayarı kaydedildi.'}
          </Typography>
        </Stack>
      )}

      <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2} justifyContent="space-between">
        <Button variant="contained" onClick={() => navigate('/')}>
          Geri dön
        </Button>
        <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
          <Button
            variant="contained"
            onClick={handleSaveCrop}
            disabled={!currentCropArea || (isCoverSelected && savingCover)}
          >
            {isCoverSelected ? 'Kapak görselini cropla' : 'Bu crop ayarını tüm görsellere uygula'}
          </Button>
          <Button
            variant="contained"
            onClick={() => navigate('/bulk-crop')}
            disabled={!canProceed}
          >
            Devam et
          </Button>
        </Stack>
      </Stack>
    </Stack>
  );
};

export default CropStep;
