'use client'

import { useState, useRef, useCallback } from 'react'
import Cropper from 'react-easy-crop'
import type { Area } from 'react-easy-crop'
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Slider } from '@/components/ui/slider'
import { UserAvatar } from './user-avatar'
import { Upload, Loader2, Trash2, ZoomIn } from 'lucide-react'
import { trpc } from '@/lib/trpc/client'
import { toast } from 'sonner'

type AvatarUploadProps = {
  user: {
    name?: string | null
    email?: string | null
    profileImageKey?: string | null
  }
  currentAvatarUrl?: string | null
  onUploadComplete?: () => void
  children?: React.ReactNode
}

const MAX_SIZE_MB = 5
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']

/**
 * Crop an image client-side using canvas and return a Blob.
 */
async function getCroppedImg(imageSrc: string, pixelCrop: Area): Promise<Blob> {
  const image = new Image()
  image.crossOrigin = 'anonymous'

  await new Promise<void>((resolve, reject) => {
    image.onload = () => resolve()
    image.onerror = reject
    image.src = imageSrc
  })

  const canvas = document.createElement('canvas')
  canvas.width = pixelCrop.width
  canvas.height = pixelCrop.height
  const ctx = canvas.getContext('2d')!

  ctx.drawImage(
    image,
    pixelCrop.x,
    pixelCrop.y,
    pixelCrop.width,
    pixelCrop.height,
    0,
    0,
    pixelCrop.width,
    pixelCrop.height
  )

  return new Promise<Blob>((resolve, reject) => {
    canvas.toBlob(
      (blob) => {
        if (blob) resolve(blob)
        else reject(new Error('Canvas toBlob failed'))
      },
      'image/jpeg',
      0.9
    )
  })
}

export function AvatarUpload({
  user,
  currentAvatarUrl,
  onUploadComplete,
  children,
}: AvatarUploadProps) {
  const [open, setOpen] = useState(false)
  const [imageSrc, setImageSrc] = useState<string | null>(null)
  const [crop, setCrop] = useState({ x: 0, y: 0 })
  const [zoom, setZoom] = useState(1)
  const [croppedAreaPixels, setCroppedAreaPixels] = useState<Area | null>(null)
  const [isUploading, setIsUploading] = useState(false)
  const [isDeleting, setIsDeleting] = useState(false)
  const fileInputRef = useRef<HTMLInputElement>(null)

  const utils = trpc.useUtils()
  const getUploadUrl = trpc.avatar.getUploadUrl.useMutation()
  const confirmUpload = trpc.avatar.confirmUpload.useMutation()
  const deleteAvatar = trpc.avatar.delete.useMutation()

  const onCropComplete = useCallback((_croppedArea: Area, croppedPixels: Area) => {
    setCroppedAreaPixels(croppedPixels)
  }, [])

  const handleFileSelect = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0]
    if (!file) return

    if (!ALLOWED_TYPES.includes(file.type)) {
      toast.error('Invalid file type. Please upload a JPEG, PNG, GIF, or WebP image.')
      return
    }

    if (file.size > MAX_SIZE_MB * 1024 * 1024) {
      toast.error(`File too large. Maximum size is ${MAX_SIZE_MB}MB.`)
      return
    }

    const reader = new FileReader()
    reader.onload = (ev) => {
      setImageSrc(ev.target?.result as string)
      setCrop({ x: 0, y: 0 })
      setZoom(1)
    }
    reader.readAsDataURL(file)
  }, [])

  const handleUpload = async () => {
    if (!imageSrc || !croppedAreaPixels) return

    setIsUploading(true)
    try {
      // Crop the image client-side
      const croppedBlob = await getCroppedImg(imageSrc, croppedAreaPixels)

      // Get pre-signed upload URL
      const { uploadUrl, key, providerType } = await getUploadUrl.mutateAsync({
        fileName: 'avatar.jpg',
        contentType: 'image/jpeg',
      })

      // Upload cropped blob directly to storage
      let uploadResponse: Response
      try {
        uploadResponse = await fetch(uploadUrl, {
          method: 'PUT',
          body: croppedBlob,
          headers: {
            'Content-Type': 'image/jpeg',
          },
        })
      } catch (fetchError) {
        console.error('Avatar upload network error (possible CORS issue):', fetchError)
        throw new Error('Network error uploading file. The storage server may not be reachable.')
      }

      if (!uploadResponse.ok) {
        console.error('Avatar upload failed:', uploadResponse.status, uploadResponse.statusText)
        throw new Error(`Upload failed (${uploadResponse.status}). Please try again.`)
      }

      // Confirm upload
      await confirmUpload.mutateAsync({ key, providerType })

      // Invalidate avatar query
      utils.avatar.getUrl.invalidate()

      toast.success('Avatar updated successfully')
      setOpen(false)
      resetState()
      onUploadComplete?.()
    } catch (error) {
      console.error('Upload error:', error)
      toast.error('Failed to upload avatar. Please try again.')
    } finally {
      setIsUploading(false)
    }
  }

  const handleDelete = async () => {
    setIsDeleting(true)
    try {
      await deleteAvatar.mutateAsync()
      utils.avatar.getUrl.invalidate()
      toast.success('Avatar removed')
      setOpen(false)
      onUploadComplete?.()
    } catch (error) {
      console.error('Delete error:', error)
      toast.error('Failed to remove avatar')
    } finally {
      setIsDeleting(false)
    }
  }

  const resetState = () => {
    setImageSrc(null)
    setCrop({ x: 0, y: 0 })
    setZoom(1)
    setCroppedAreaPixels(null)
    if (fileInputRef.current) fileInputRef.current.value = ''
  }

  const handleCancel = () => {
    resetState()
    setOpen(false)
  }

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        {children || (
          <div className="cursor-pointer">
            <UserAvatar user={user} avatarUrl={currentAvatarUrl} showEditOverlay />
          </div>
        )}
      </DialogTrigger>
      <DialogContent className="sm:max-w-md">
        <DialogHeader>
          <DialogTitle>Update Profile Picture</DialogTitle>
          <DialogDescription>
            {imageSrc
              ? 'Drag to reposition and use the slider to zoom.'
              : 'Upload a new profile picture. Allowed formats: JPEG, PNG, GIF, WebP.'}
          </DialogDescription>
        </DialogHeader>

        <div className="space-y-4 py-4">
          {imageSrc ? (
            <>
              {/* Cropper */}
              <div className="relative w-full h-64 bg-muted rounded-lg overflow-hidden">
                <Cropper
                  image={imageSrc}
                  crop={crop}
                  zoom={zoom}
                  aspect={1}
                  cropShape="round"
                  showGrid={false}
                  onCropChange={setCrop}
                  onCropComplete={onCropComplete}
                  onZoomChange={setZoom}
                />
              </div>

              {/* Zoom slider */}
              <div className="flex items-center gap-3 px-1">
                <ZoomIn className="h-4 w-4 text-muted-foreground shrink-0" />
                <Slider
                  value={[zoom]}
                  min={1}
                  max={3}
                  step={0.1}
                  onValueChange={([val]) => setZoom(val)}
                  className="flex-1"
                />
              </div>

              {/* Change image button */}
              <Button
                variant="ghost"
                size="sm"
                onClick={() => {
                  resetState()
                  fileInputRef.current?.click()
                }}
                className="w-full"
              >
                Choose a different image
              </Button>
            </>
          ) : (
            <>
              {/* Current avatar preview */}
              <div className="flex justify-center">
                <UserAvatar
                  user={user}
                  avatarUrl={currentAvatarUrl}
                  size="xl"
                />
              </div>

              {/* File input */}
              <div className="space-y-2">
                <Label htmlFor="avatar">Select image</Label>
                <Input
                  ref={fileInputRef}
                  id="avatar"
                  type="file"
                  accept={ALLOWED_TYPES.join(',')}
                  onChange={handleFileSelect}
                  className="cursor-pointer"
                />
              </div>
            </>
          )}
        </div>

        <DialogFooter className="flex-col gap-2 sm:flex-row">
          {currentAvatarUrl && !imageSrc && (
            <Button
              variant="destructive"
              onClick={handleDelete}
              disabled={isDeleting}
              className="w-full sm:w-auto"
            >
              {isDeleting ? (
                <Loader2 className="mr-2 h-4 w-4 animate-spin" />
              ) : (
                <Trash2 className="mr-2 h-4 w-4" />
              )}
              Remove
            </Button>
          )}

          <div className="flex gap-2 w-full sm:w-auto">
            <Button variant="outline" onClick={handleCancel} className="flex-1">
              Cancel
            </Button>
            {imageSrc && (
              <Button
                onClick={handleUpload}
                disabled={!croppedAreaPixels || isUploading}
                className="flex-1"
              >
                {isUploading ? (
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                ) : (
                  <Upload className="mr-2 h-4 w-4" />
                )}
                Upload
              </Button>
            )}
          </div>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}
