import React, { useState, useEffect, memo } from 'react'
import type { ItemStack } from '../../types'
import { useTextures } from '../../context/TextureContext'
import { useScale } from '../../context/ScaleContext'
import { useDataUrl, isTextureFailed } from '../../cache/textureCache'
import { renderBlockIcon } from '../../cache/blockRenderer'

interface ItemCanvasProps {
  item: ItemStack
  size?: number
  /** Hide item count overlay */
  noCount?: boolean
  /** Hide durability bar */
  noDurability?: boolean
  className?: string
  style?: React.CSSProperties
}

function getDurabilityColor(current: number, max: number): string {
  const ratio = current / max
  if (ratio > 0.6) return '#55ff55'
  if (ratio > 0.3) return '#ffff55'
  return '#ff5555'
}

/** Resolve item texture source: direct override, block render, or URL lookup. */
function useItemTextureSrc(item: ItemStack): {
  src: string | null
  failed: boolean
  loading: boolean
} {
  const textures = useTextures()

  // Block texture: always run effect for blockTexture case
  const blockConfig = item.blockTexture ?? null
  const [blockDataUrl, setBlockDataUrl] = useState<string | null>(null)
  const [blockFailed, setBlockFailed] = useState(false)

  useEffect(() => {
    if (!blockConfig) return
    let cancelled = false
    renderBlockIcon(
      blockConfig.source,
      blockConfig.top.slice,
      blockConfig.left.slice,
      blockConfig.right.slice,
    )
      .then((url) => {
        if (!cancelled) setBlockDataUrl(url)
      })
      .catch(() => {
        if (!cancelled) setBlockFailed(true)
      })
    return () => {
      cancelled = true
    }
  }, [
    blockConfig?.source,
    blockConfig ? String(blockConfig.top.slice) : '',
    blockConfig ? String(blockConfig.left.slice) : '',
    blockConfig ? String(blockConfig.right.slice) : '',
  ])

  // Reset block state when switching away from blockTexture
  useEffect(() => {
    if (!blockConfig) {
      setBlockDataUrl(null)
      setBlockFailed(false)
    }
  }, [blockConfig])

  // Direct texture (string) - use cache
  const directUrl =
    typeof item.texture === 'string' ? item.texture : null
  const directDataUrl = useDataUrl(directUrl)

  // Default URL lookup
  const primaryUrl = blockConfig ? '' : (typeof item.texture === 'string' ? '' : textures.getItemTextureUrl(item))
  const fallbackUrl =
    !blockConfig &&
    !item.textureKey &&
    item.name
      ? textures.getBlockTextureUrl(item)
      : null
  const primaryDataUrl = useDataUrl(primaryUrl || null)
  const primaryFailed = primaryDataUrl === null || isTextureFailed(primaryUrl)

  const [loadFallback, setLoadFallback] = useState(false)
  useEffect(() => {
    if (primaryFailed && fallbackUrl) setLoadFallback(true)
    else setLoadFallback(false)
  }, [primaryFailed, fallbackUrl])
  const fallbackDataUrl = useDataUrl(loadFallback ? fallbackUrl : null)

  // Resolve final src by priority
  if (typeof item.texture === 'string') {
    return {
      src: directDataUrl ?? null,
      failed: directDataUrl === null || isTextureFailed(item.texture),
      loading: directDataUrl === undefined,
    }
  }
  if (item.texture instanceof HTMLImageElement) {
    const img = item.texture
    return {
      src: img.complete && img.naturalWidth > 0 ? img.src : null,
      failed: false,
      loading: !img.complete,
    }
  }
  if (blockConfig) {
    return {
      src: blockDataUrl,
      failed: blockFailed,
      loading: !blockDataUrl && !blockFailed,
    }
  }

  const src = loadFallback ? fallbackDataUrl : primaryDataUrl
  const failed = loadFallback
    ? (fallbackDataUrl === null || isTextureFailed(fallbackUrl ?? ''))
    : primaryFailed && !fallbackUrl

  return {
    src: src ?? null,
    failed,
    loading: src === undefined,
  }
}

/** Renders a single item: texture as <img>, count as <span>, durability as CSS bars. */
export const ItemCanvas = memo(function ItemCanvas({
  item,
  size,
  noCount = false,
  noDurability = false,
  className,
  style,
}: ItemCanvasProps) {
  const { contentSize, pixelSize } = useScale()
  const renderSize = size ?? contentSize

  const { src, failed, loading } = useItemTextureSrc(item)

  const hasDurability =
    !noDurability &&
    item.durability !== undefined &&
    item.maxDurability !== undefined &&
    item.durability < item.maxDurability

  const barColor = hasDurability
    ? getDurabilityColor(item.durability!, item.maxDurability!)
    : '#55ff55'

  // Font size for count: ~38% of slot size, min 7px, shadow offset = 1 scaled pixel
  const countFontSize = Math.max(7, Math.round(renderSize * 0.5))
  const shadow = Math.max(1, Math.round(pixelSize))

  return (
    <div
      className={['mc-inv-item', className].filter(Boolean).join(' ')}
      style={{
        position: 'relative',
        width: renderSize,
        height: renderSize,
        flexShrink: 0,
        ...style,
      }}
    >
      {failed ? (
        /* Missing texture — magenta/black checkerboard */
        <div className="mc-inv-item-placeholder" style={{
          width: '100%',
          height: '100%',
          background: 'linear-gradient(45deg, #8b008b 25%, #000 25%, #000 50%, #8b008b 50%, #8b008b 75%, #000 75%)',
          backgroundSize: `${renderSize / 2}px ${renderSize / 2}px`,
        }} />
      ) : src ? (
        /* Loaded — render cached data URL; no onError needed */
        <img
          className="mc-inv-item-image"
          src={src}
          alt=""
          aria-hidden
          draggable={false}
          style={{
            width: '100%',
            height: '100%',
            imageRendering: 'pixelated',
            display: 'block',
            pointerEvents: 'none',
          }}
        />
      ) : null /* still loading — render nothing (slot stays empty) */}

      {/* Durability bar — vanilla layout: x=2, y=13 in 16×16 item area */}
      {hasDurability && (() => {
        // Derive mcPx from renderSize so the bar always fits the container,
        // even at fractional scales where contentSize ≠ 16 * round(scale).
        const mcPx = Math.max(1, Math.floor(renderSize / 16))
        const barLeft = 2 * mcPx
        const bgBottom = mcPx
        const bgWidth = 13 * mcPx
        const bgHeight = 2 * mcPx
        const ratio = item.durability! / item.maxDurability!
        const fillWidth = Math.round(13 * ratio) * mcPx
        const fillHeight = mcPx
        const fillBottom = 2 * mcPx
        return (
          <>
            <div className="mc-inv-item-durability-bg" style={{
              position: 'absolute',
              bottom: bgBottom,
              left: barLeft,
              width: bgWidth,
              height: bgHeight,
              background: '#000',
              pointerEvents: 'none',
            }} />
            <div className="mc-inv-item-durability-bar" style={{
              position: 'absolute',
              bottom: fillBottom,
              left: barLeft,
              width: fillWidth,
              height: fillHeight,
              background: barColor,
              pointerEvents: 'none',
            }} />
          </>
        )
      })()}

      {/* Item count */}
      {!noCount && item.count > 1 && (
        <span className="mc-inv-item-count" style={{
          position: 'absolute',
          bottom: 0,
          right: 0,
          fontSize: countFontSize,
          fontFamily: "'Minecraftia', 'Minecraft', monospace",
          fontWeight: 'normal',
          color: '#ffffff',
          lineHeight: 1,
          pointerEvents: 'none',
          // Double shadow trick: dark shadow at +1,+1 for Minecraft count text look
          textShadow: `${shadow}px ${shadow}px 0 rgba(0,0,0,0.6)`,
          userSelect: 'none',
          // Prevent wrapping
          whiteSpace: 'nowrap',
        }}>
          {item.count}
        </span>
      )}
    </div>
  )
})
