import { useCallback, useEffect, useState } from 'react'
import * as Dialog from '@radix-ui/react-dialog'
import Cropper, { type Area } from 'react-easy-crop'
import { X } from 'lucide-react'
import { MotionDialogContent } from '../../../../shared/ui/MotionDialog/MotionDialog'

import './AvatarCropModal.scss'

type AvatarCropModalProps = {
  open: boolean
  imageSrc: string
  onCancel: () => void
  onConfirm: (file: File, previewUrl: string) => void
}

function createImage(src: string) {
  return new Promise<HTMLImageElement>((resolve, reject) => {
    const image = new Image()

    image.onload = () => resolve(image)
    image.onerror = reject
    image.src = src
  })
}

async function createCroppedAvatarFile(imageSrc: string, crop: Area) {
  const image = await createImage(imageSrc)
  const canvas = document.createElement('canvas')
  const context = canvas.getContext('2d')

  const outputSize = 512

  canvas.width = outputSize
  canvas.height = outputSize

  if (!context) {
    throw new Error('Не удалось подготовить изображение')
  }

  context.drawImage(
    image,
    crop.x,
    crop.y,
    crop.width,
    crop.height,
    0,
    0,
    outputSize,
    outputSize,
  )

  const blob = await new Promise<Blob | null>((resolve) => {
    canvas.toBlob(resolve, 'image/png', 0.92)
  })

  if (!blob) {
    throw new Error('Не удалось обрезать изображение')
  }

  return new File([blob], 'avatar.png', {
    type: 'image/png',
  })
}

export function AvatarCropModal({
  open,
  imageSrc,
  onCancel,
  onConfirm,
}: AvatarCropModalProps) {
  const [crop, setCrop] = useState({ x: 0, y: 0 })
  const [zoom, setZoom] = useState(1)
  const [croppedAreaPixels, setCroppedAreaPixels] = useState<Area | null>(null)
  const [isProcessing, setIsProcessing] = useState(false)

  useEffect(() => {
    if (!open) return

    setCrop({ x: 0, y: 0 })
    setZoom(1)
    setCroppedAreaPixels(null)
    setIsProcessing(false)
  }, [open, imageSrc])

  const handleCropComplete = useCallback(
    (_croppedArea: Area, nextCroppedAreaPixels: Area) => {
      setCroppedAreaPixels(nextCroppedAreaPixels)
    },
    [],
  )

  async function handleConfirm() {
    if (!croppedAreaPixels || isProcessing) return

    setIsProcessing(true)

    try {
      const file = await createCroppedAvatarFile(imageSrc, croppedAreaPixels)
      const previewUrl = URL.createObjectURL(file)

      onConfirm(file, previewUrl)
    } finally {
      setIsProcessing(false)
    }
  }

  return (
    <Dialog.Root
      open={open}
      onOpenChange={(nextOpen) => {
        if (!nextOpen) {
          onCancel()
        }
      }}
    >
      <MotionDialogContent
        open={open}
        overlayClassName="avatar-crop-modal__overlay"
        contentClassName="avatar-crop-modal"
      >
          <div className="avatar-crop-modal__header">
            <Dialog.Title>Настройка фото</Dialog.Title>

            <button
              className="avatar-crop-modal__close"
              type="button"
              onClick={onCancel}
              disabled={isProcessing}
            >
              <X size={20} />
            </button>
          </div>

          <div className="avatar-crop-modal__cropper">
            <Cropper
              image={imageSrc}
              crop={crop}
              zoom={zoom}
              aspect={1}
              cropShape="round"
              showGrid={false}
              onCropChange={setCrop}
              onZoomChange={setZoom}
              onCropComplete={handleCropComplete}
            />
          </div>

          <div className="avatar-crop-modal__controls">
            <label>
              <span>Масштаб</span>

              <input
                type="range"
                min="1"
                max="3"
                step="0.05"
                value={zoom}
                onChange={(event) => setZoom(Number(event.target.value))}
                disabled={isProcessing}
              />
            </label>
          </div>

          <div className="avatar-crop-modal__footer">
            <button
              className="avatar-crop-modal__cancel"
              type="button"
              onClick={onCancel}
              disabled={isProcessing}
            >
              Отмена
            </button>

            <button
              className="avatar-crop-modal__submit"
              type="button"
              onClick={handleConfirm}
              disabled={isProcessing}
            >
              {isProcessing ? 'Подготовка...' : 'Установить фотографию'}
            </button>
          </div>
      </MotionDialogContent>
    </Dialog.Root>
  )
}
