import React, { useMemo, useRef, useState } from 'react'

function formatBytes(bytes) {
  const value = Number(bytes || 0)
  if (!Number.isFinite(value) || value <= 0) return null
  if (value < 1024 * 1024) return `${Math.round(value / 1024)} KB`
  return `${(value / (1024 * 1024)).toFixed(1)} MB`
}

export default function WorldMediaUploadField({
  label,
  slot,
  value,
  previewUrl,
  emptyLabel,
  helperText,
  uploadUrl,
  deleteUrl,
  worldId = null,
  onChange,
  isTemporaryValue = false,
  accept = 'image/jpeg,image/png,image/webp',
  maxFileSizeMb = 6,
}) {
  const inputRef = useRef(null)
  const [dragging, setDragging] = useState(false)
  const [uploading, setUploading] = useState(false)
  const [error, setError] = useState('')
  const [meta, setMeta] = useState(null)

  const csrfToken = useMemo(() => {
    if (typeof document === 'undefined') {
      return ''
    }

    return document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''
  }, [])

  const deleteTemporaryUpload = async (path) => {
    if (!deleteUrl || !path) return

    const response = await fetch(deleteUrl, {
      method: 'DELETE',
      headers: {
        'Content-Type': 'application/json',
        'X-CSRF-TOKEN': csrfToken,
        Accept: 'application/json',
      },
      credentials: 'same-origin',
      body: JSON.stringify({
        path,
        world_id: worldId || undefined,
      }),
    })

    const payload = await response.json().catch(() => ({}))
    if (!response.ok) {
      throw new Error(payload?.message || payload?.error || 'Could not remove uploaded image.')
    }
  }

  const handleFile = async (file) => {
    if (!file || uploading) return

    const allowed = ['image/jpeg', 'image/png', 'image/webp']
    if (!allowed.includes(String(file.type || '').toLowerCase())) {
      setError('Use a JPG, PNG, or WEBP image.')
      return
    }

    if (file.size > maxFileSizeMb * 1024 * 1024) {
      setError(`Image is too large. Maximum allowed size is ${maxFileSizeMb} MB.`)
      return
    }

    setUploading(true)
    setError('')

    try {
      if (value && isTemporaryValue) {
        await deleteTemporaryUpload(value)
      }

      const body = new FormData()
      body.append('slot', slot)
      body.append('image', file)
      if (worldId) {
        body.append('world_id', String(worldId))
      }

      const response = await fetch(uploadUrl, {
        method: 'POST',
        headers: {
          'X-CSRF-TOKEN': csrfToken,
          Accept: 'application/json',
        },
        credentials: 'same-origin',
        body,
      })

      const payload = await response.json().catch(() => ({}))
      if (!response.ok) {
        throw new Error(payload?.message || payload?.error || 'Upload failed.')
      }

      setMeta({
        width: payload?.width || null,
        height: payload?.height || null,
        size: formatBytes(payload?.size_bytes),
      })
      onChange?.({ path: payload?.path || '', url: payload?.url || '' })
    } catch (uploadError) {
      setError(uploadError?.message || 'Upload failed.')
    } finally {
      setUploading(false)
      if (inputRef.current) {
        inputRef.current.value = ''
      }
    }
  }

  return (
    <div className="grid gap-3 text-sm text-slate-300">
      <div className="flex items-center justify-between gap-3">
        <span className="text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500">{label}</span>
        {value ? (
          <button
            type="button"
            onClick={async (event) => {
              event.stopPropagation()
              setError('')
              setMeta(null)

              try {
                if (value && isTemporaryValue) {
                  setUploading(true)
                  await deleteTemporaryUpload(value)
                }
                onChange?.({ path: '', url: '' })
              } catch (deleteError) {
                setError(deleteError?.message || 'Could not remove uploaded image.')
              } finally {
                setUploading(false)
              }
            }}
            disabled={uploading}
            className="rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.14em] text-white"
          >
            Clear
          </button>
        ) : null}
      </div>

      <div
        role="button"
        tabIndex={0}
        onClick={() => !uploading && inputRef.current?.click()}
        onKeyDown={(event) => {
          if (uploading) return
          if (event.key === 'Enter' || event.key === ' ') {
            event.preventDefault()
            inputRef.current?.click()
          }
        }}
        onDragOver={(event) => {
          event.preventDefault()
          if (!uploading) setDragging(true)
        }}
        onDragEnter={(event) => {
          event.preventDefault()
          if (!uploading) setDragging(true)
        }}
        onDragLeave={(event) => {
          event.preventDefault()
          setDragging(false)
        }}
        onDrop={(event) => {
          event.preventDefault()
          setDragging(false)
          void handleFile(event.dataTransfer?.files?.[0])
        }}
        className={[
          'rounded-[24px] border border-dashed px-5 py-5 transition outline-none',
          uploading
            ? 'cursor-progress border-sky-300/35 bg-sky-400/10'
            : dragging
              ? 'cursor-pointer border-sky-300/50 bg-sky-400/12'
              : 'cursor-pointer border-white/10 bg-black/20 hover:border-white/20 hover:bg-white/[0.04]',
        ].join(' ')}
      >
        <div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
          <div className="flex items-start gap-4">
            <div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl border border-sky-300/20 bg-sky-400/10 text-sky-100">
              <i className={`fa-solid ${uploading ? 'fa-circle-notch fa-spin' : 'fa-cloud-arrow-up'}`} />
            </div>
            <div>
              <div className="text-sm font-semibold text-white">{uploading ? 'Uploading image…' : 'Drop image here or browse'}</div>
              <div className="mt-1 text-xs leading-5 text-slate-400">{helperText}</div>
              <div className="mt-2 flex flex-wrap gap-2 text-[11px] text-slate-400">
                <span className="rounded-full border border-white/10 bg-white/[0.04] px-2.5 py-1">JPG</span>
                <span className="rounded-full border border-white/10 bg-white/[0.04] px-2.5 py-1">PNG</span>
                <span className="rounded-full border border-white/10 bg-white/[0.04] px-2.5 py-1">WEBP</span>
                <span className="rounded-full border border-white/10 bg-white/[0.04] px-2.5 py-1">Max {maxFileSizeMb} MB</span>
              </div>
            </div>
          </div>

          <div className="h-28 w-full overflow-hidden rounded-[20px] border border-white/10 bg-slate-950 lg:w-44">
            {previewUrl ? (
              <img src={previewUrl} alt="" className="h-full w-full object-cover" />
            ) : (
              <div className="flex h-full items-center justify-center px-4 text-center text-sm text-slate-500">{emptyLabel}</div>
            )}
          </div>
        </div>

        {value ? <div className="mt-4 truncate rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-xs text-slate-400">Stored path: <span className="text-slate-200">{value}</span></div> : null}
        {meta ? <div className="mt-3 text-xs text-slate-400">Optimized to {meta.width}×{meta.height}{meta.size ? ` • ${meta.size}` : ''}</div> : null}
        {error ? <div className="mt-3 rounded-2xl border border-rose-300/20 bg-rose-400/10 px-4 py-3 text-sm text-rose-100">{error}</div> : null}

        <input
          ref={inputRef}
          type="file"
          accept={accept}
          className="hidden"
          disabled={uploading}
          onChange={(event) => {
            void handleFile(event.target.files?.[0])
          }}
        />
      </div>
    </div>
  )
}