import { useEffect, useRef, useState } from 'react'
import { Button } from '@/components/ui/Button'
import { TextField } from '@/components/ui/TextField'
import { PlantIcon } from '@/components/plants/PlantIcon'
import { useRemovePlanting, useUpdatePlanting } from '@/lib/objects'
import type { Plant } from '@/lib/plants'
import { computeDerivedCount, type EditorPlanting } from '@/lib/plantings'
import { cmFromSpacing, spacingFromCm, spacingUnitLabel, type UnitPref } from '@/lib/units'
import { MIN_RADIUS_CM } from './shared'
import { useEditorStore } from './store'

/**
 * Property panel for the selected plop. Radius/label/date/count commit a PATCH on
 * blur (carrying the version); the count field shows the live derived value as a
 * placeholder and takes an override when typed. "Remove" soft-removes (keeps the
 * row with removed_at); "Change plant" opens the picker via onChangePlant. While
 * the plop is dragged/resized on the canvas, it reads livePlanting for live
 * feedback (subscribed here, not at the page level, so a drag only re-renders
 * this panel).
 */
export function PlopInspector({
  plop,
  plant,
  gardenId,
  unit,
  onChangePlant,
  onClose,
  onAddNote,
  readOnly = false,
}: {
  plop: EditorPlanting
  plant?: Plant
  gardenId: number
  unit: UnitPref
  onChangePlant: () => void
  onClose: () => void
  /** Scope the journal to this plop and open it — the plop parallel of the bed
   *  inspector's "add note" (#85). Offered to viewers too (to READ the plop's
   *  notes, like the bed inspector does); the journal's composer is separately
   *  gated on edit rights, so a viewer just sees the entries. */
  onAddNote?: () => void
  readOnly?: boolean
}) {
  const update = useUpdatePlanting(gardenId)
  const remove = useRemovePlanting(gardenId)
  const livePlanting = useEditorStore((s) => s.livePlanting)
  const rootRef = useRef<HTMLDivElement>(null)

  // The plop with any in-flight drag/resize geometry applied.
  const p = livePlanting && livePlanting.id === plop.id ? livePlanting : plop

  const [radius, setRadius] = useState(String(spacingFromCm(p.radiusCm, unit)))
  const [count, setCount] = useState(p.count != null ? String(p.count) : '')
  const [label, setLabel] = useState(p.label ?? '')
  const [planted, setPlanted] = useState(p.plantedAt ?? '')

  // Re-sync when the plop changes underneath us (a drag/resize or a server row),
  // unless the user is editing a field here.
  useEffect(() => {
    if (rootRef.current?.contains(document.activeElement)) return
    setRadius(String(spacingFromCm(p.radiusCm, unit)))
    setCount(p.count != null ? String(p.count) : '')
    setLabel(p.label ?? '')
    setPlanted(p.plantedAt ?? '')
  }, [p.version, p.radiusCm, p.count, p.label, p.plantedAt, unit])

  const patch = (fields: Omit<Parameters<typeof update.mutate>[0], 'id' | 'version'>) => {
    if (readOnly) return // a blur mustn't fire a mutation if the role changed mid-edit
    update.mutate({ id: plop.id, version: plop.version, ...fields })
  }

  const u = spacingUnitLabel(unit)
  const derived = plant ? computeDerivedCount(p.radiusCm, plant.spacingCm) : p.derivedCount

  function commitRadius() {
    const v = Number(radius)
    if (radius.trim() === '' || !Number.isFinite(v)) {
      setRadius(String(spacingFromCm(p.radiusCm, unit))) // reset stale/invalid text
      return
    }
    const cm = Math.max(MIN_RADIUS_CM, cmFromSpacing(v, unit))
    if (cm !== p.radiusCm) patch({ radiusCm: cm })
  }

  function commitCount() {
    if (count.trim() === '') {
      if (p.count != null) patch({ count: null }) // restore derived
      return
    }
    const n = Number(count)
    if (!Number.isInteger(n) || n < 1) {
      setCount(p.count != null ? String(p.count) : '') // reject invalid, restore
      return
    }
    if (n !== p.count) patch({ count: n })
  }

  function commitPlanted() {
    const next = planted === '' ? null : planted
    if (next !== (p.plantedAt ?? null)) patch({ plantedAt: next })
  }

  return (
    <div ref={rootRef} className="flex flex-col gap-3">
      <div className="flex items-center justify-between">
        <h2 className="text-sm font-semibold text-fg">Plant</h2>
        <button
          type="button"
          onClick={onClose}
          className="rounded px-1.5 text-sm text-muted hover:text-fg"
          aria-label="Close inspector"
        >
          ✕
        </button>
      </div>

      {readOnly && (
        <p className="rounded-md bg-border/40 px-2 py-1 text-xs text-muted">View only — you can't edit this garden.</p>
      )}

      <div className="flex items-center gap-2 rounded-lg border border-border p-2">
        {plant ? (
          <PlantIcon color={plant.color} icon={plant.icon} className="h-9 w-9 rounded-md text-xl" />
        ) : (
          <span className="grid h-9 w-9 place-items-center rounded-md bg-border/50 text-muted">?</span>
        )}
        <span className="min-w-0 flex-1 truncate text-sm font-medium text-fg">{plant?.name ?? 'Unknown plant'}</span>
        {!readOnly && (
          <Button variant="ghost" className="px-2 py-1 text-xs" onClick={onChangePlant}>
            Change
          </Button>
        )}
      </div>

      <fieldset disabled={readOnly} className="flex min-w-0 flex-col gap-3 border-0 p-0">
        <div className="grid grid-cols-2 gap-2">
          <TextField
            label={`Radius (${u})`}
            name="radius"
            type="number"
            inputMode="decimal"
            step="any"
            min="0"
            value={radius}
            onChange={(e) => setRadius(e.target.value)}
            onBlur={commitRadius}
          />
          <TextField
            label="Count"
            name="count"
            type="number"
            inputMode="numeric"
            step="1"
            min="1"
            placeholder={`${derived} (auto)`}
            value={count}
            onChange={(e) => setCount(e.target.value)}
            onBlur={commitCount}
            hint={p.count != null ? 'Override — clear for auto' : 'Auto from area ÷ spacing²'}
          />
        </div>

        <TextField
          label="Label (optional)"
          name="label"
          value={label}
          onChange={(e) => setLabel(e.target.value)}
          onBlur={() => label !== (p.label ?? '') && patch({ label: label.trim() || null })}
        />

        <TextField
          label="Planted"
          name="planted"
          type="date"
          value={planted}
          onChange={(e) => setPlanted(e.target.value)}
          onBlur={commitPlanted}
        />
      </fieldset>

      {onAddNote && (
        <Button variant="ghost" className="justify-start px-2 py-1 text-sm" onClick={onAddNote}>
          📓 {readOnly ? 'Notes about this plant' : 'Add a note about this plant'}
        </Button>
      )}

      {!readOnly && (
        <Button
          variant="ghost"
          className="text-red-600 dark:text-red-400"
          disabled={remove.isPending}
          onClick={() => {
            onClose()
            remove.mutate({ id: plop.id, version: plop.version })
          }}
        >
          Remove plant
        </Button>
      )}
    </div>
  )
}
