import { useState, type FormEvent } from 'react'
import { Modal } from '@/components/ui/Modal'
import { Alert } from '@/components/ui/Alert'
import { Button } from '@/components/ui/Button'
import { Select } from '@/components/ui/Select'
import { TextArea } from '@/components/ui/TextArea'
import { TextField } from '@/components/ui/TextField'
import { errorMessage } from '@/lib/api'
import {
  CATEGORY_LABELS,
  PLANT_CATEGORIES,
  conflictPlant,
  useCreatePlant,
  useUpdatePlant,
  type Plant,
  type PlantCategory,
  type PlantInput,
} from '@/lib/plants'
import { safeExternalUrl } from '@/lib/seedLots'
import { cmFromSpacing, spacingFromCm, spacingUnitLabel, type UnitPref } from '@/lib/units'

const DEFAULT_COLOR = '#4a7c3f'
const DEFAULT_ICON = '🌱'

const categoryOptions = PLANT_CATEGORIES.map((c) => ({ value: c, label: CATEGORY_LABELS[c] }))

/** Expand a #rgb shorthand to #rrggbb so the native color input renders it. */
function expandHex(color: string): string {
  if (/^#[0-9a-fA-F]{3}$/.test(color)) {
    const [, r, g, b] = color
    return `#${r}${r}${g}${g}${b}${b}`
  }
  return /^#[0-9a-fA-F]{6}$/.test(color) ? color : DEFAULT_COLOR
}

/**
 * Create or edit a custom plant. `plant` puts it in edit mode; `template` (a
 * built-in or another plant, used by "Duplicate") pre-fills a fresh create. A
 * 409 rebases the form onto the server's current row. Spacing is entered in the
 * page's unit and converted to centimeters for the API.
 */
export function PlantFormModal({
  plant,
  template,
  unit,
  onClose,
}: {
  plant?: Plant
  template?: Plant
  unit: UnitPref
  onClose: () => void
}) {
  const isEdit = !!plant
  const source = plant ?? template
  const create = useCreatePlant()
  const update = useUpdatePlant()
  const pending = create.isPending || update.isPending

  const [name, setName] = useState(source ? (isEdit ? source.name : `${source.name} (copy)`) : '')
  const [category, setCategory] = useState<PlantCategory>(source?.category ?? 'vegetable')
  const [spacing, setSpacing] = useState(String(spacingFromCm(source?.spacingCm ?? 30, unit)))
  const [color, setColor] = useState(expandHex(source?.color ?? DEFAULT_COLOR))
  const [icon, setIcon] = useState(source?.icon ?? DEFAULT_ICON)
  const [days, setDays] = useState(source?.daysToMaturity != null ? String(source.daysToMaturity) : '')
  const [sourceUrl, setSourceUrl] = useState(source?.sourceUrl ?? '')
  const [vendor, setVendor] = useState(source?.vendor ?? '')
  const [notes, setNotes] = useState(source?.notes ?? '')
  const [version, setVersion] = useState(plant?.version ?? 0)
  const [conflict, setConflict] = useState<string | null>(null)
  const [formError, setFormError] = useState<string | null>(null)
  const unitLabel = spacingUnitLabel(unit)

  async function onSubmit(e: FormEvent) {
    e.preventDefault()
    setFormError(null)
    setConflict(null)

    if (!name.trim()) {
      setFormError('Enter a name for the plant.')
      return
    }
    if (!icon.trim()) {
      setFormError('Pick an emoji icon.')
      return
    }
    const spacingCm = cmFromSpacing(parseFloat(spacing), unit)
    if (!Number.isFinite(spacingCm) || spacingCm < 1) {
      setFormError(`Spacing must be at least 1 ${unitLabel}.`)
      return
    }
    let daysToMaturity: number | null = null
    if (days.trim()) {
      // Number() (not parseInt) so "1.5" is rejected, not silently truncated to 1.
      const d = Number(days)
      if (!Number.isInteger(d) || d < 1) {
        setFormError('Days to maturity must be a whole number of days, or left blank.')
        return
      }
      daysToMaturity = d
    }

    // The server refuses anything that isn't http(s) with a host, but say so here
    // rather than letting a paste of "johnnyseeds.com" come back as a generic
    // error with no hint about which field or why.
    if (sourceUrl.trim() && !safeExternalUrl(sourceUrl.trim())) {
      setFormError('The source link needs to be a full http:// or https:// address.')
      return
    }

    const input: PlantInput = {
      name: name.trim(),
      category,
      spacingCm,
      color,
      icon: icon.trim(),
      daysToMaturity,
      sourceUrl: sourceUrl.trim(),
      vendor: vendor.trim(),
      notes: notes.trim(),
    }

    try {
      if (isEdit) {
        await update.mutateAsync({ id: plant.id, ...input, version })
      } else {
        await create.mutateAsync(input)
      }
      onClose()
    } catch (err) {
      const current = conflictPlant(err)
      if (current) {
        // Someone else changed this plant: rebase onto the fresh row so a re-save
        // applies against the current version.
        setVersion(current.version)
        setName(current.name)
        setCategory(current.category)
        setSpacing(String(spacingFromCm(current.spacingCm, unit)))
        setColor(expandHex(current.color))
        setIcon(current.icon)
        setDays(current.daysToMaturity != null ? String(current.daysToMaturity) : '')
        setNotes(current.notes)
        setConflict('This plant changed elsewhere. The latest values are shown — review and save again.')
        return
      }
      setFormError(errorMessage(err, isEdit ? 'Could not save changes.' : 'Could not create the plant.'))
    }
  }

  return (
    <Modal title={isEdit ? 'Edit plant' : 'New plant'} onClose={onClose} busy={pending}>
      <form onSubmit={onSubmit} className="flex flex-col gap-3">
        {conflict && <Alert tone="info">{conflict}</Alert>}

        <TextField label="Name" name="name" required value={name} onChange={(e) => setName(e.target.value)} />

        <div className="grid grid-cols-2 gap-3">
          <Select
            label="Category"
            name="category"
            value={category}
            onChange={(e) => setCategory(e.target.value as PlantCategory)}
            options={categoryOptions}
          />
          <TextField
            label={`Spacing (${unitLabel})`}
            name="spacing"
            type="number"
            inputMode="decimal"
            step="any"
            min="1"
            required
            value={spacing}
            onChange={(e) => setSpacing(e.target.value)}
          />
        </div>

        <div className="grid grid-cols-2 gap-3">
          <div className="flex flex-col gap-1.5">
            <label htmlFor="plant-color" className="text-sm font-medium text-fg">
              Color
            </label>
            <input
              id="plant-color"
              type="color"
              value={color}
              onChange={(e) => setColor(e.target.value)}
              className="h-10 w-full cursor-pointer rounded-md border border-border bg-surface"
            />
          </div>
          <TextField
            label="Icon (emoji)"
            name="icon"
            value={icon}
            onChange={(e) => setIcon(e.target.value)}
            hint="A single emoji, e.g. 🍅"
          />
        </div>

        <TextField
          label="Days to maturity (optional)"
          name="days"
          type="number"
          inputMode="numeric"
          step="1"
          min="1"
          value={days}
          onChange={(e) => setDays(e.target.value)}
        />

        {/* Provenance for the variety itself. What you bought and what's left
            of it is a seed lot, added from the plant card. */}
        <div className="grid grid-cols-2 gap-3">
          <TextField
            label="Vendor"
            name="vendor"
            placeholder="Johnny's Selected Seeds"
            value={vendor}
            onChange={(e) => setVendor(e.target.value)}
          />
          <TextField
            label="Source link"
            name="sourceUrl"
            type="url"
            inputMode="url"
            placeholder="https://…"
            value={sourceUrl}
            onChange={(e) => setSourceUrl(e.target.value)}
          />
        </div>

        <TextArea label="Notes" name="notes" rows={2} value={notes} onChange={(e) => setNotes(e.target.value)} />

        {formError && <Alert>{formError}</Alert>}

        <div className="mt-1 flex justify-end gap-2">
          <Button type="button" variant="ghost" onClick={onClose} disabled={pending}>
            Cancel
          </Button>
          <Button type="submit" disabled={pending}>
            {pending ? 'Saving…' : isEdit ? 'Save' : 'Create plant'}
          </Button>
        </div>
      </form>
    </Modal>
  )
}
