"use client"

import React, { useEffect, useState } from "react"
import { Loader2, Info } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
  Sheet,
  SheetContent,
  SheetHeader,
  SheetTitle,
} from "@/components/ui/sheet"
import { cn } from "@/lib/utils"
import {
  type SensorDevice,
  type SensorCreate,
  type DeviceType,
  type Protocol,
  createSensor,
  updateSensor,
} from "@/lib/api"

// ── Option maps ───────────────────────────────────────────────────────────────

const DEVICE_TYPE_OPTIONS: { value: DeviceType; label: string }[] = [
  { value: "ups",            label: "UPS" },
  { value: "generator",      label: "Generator" },
  { value: "crac",           label: "CRAC Unit" },
  { value: "chiller",        label: "Chiller" },
  { value: "ats",            label: "Transfer Switch (ATS)" },
  { value: "rack",           label: "Rack PDU" },
  { value: "network_switch", label: "Network Switch" },
  { value: "leak",           label: "Leak Sensor" },
  { value: "fire_zone",      label: "Fire / VESDA Zone" },
  { value: "custom",         label: "Custom" },
]

const PROTOCOL_OPTIONS: { value: Protocol; label: string }[] = [
  { value: "mqtt",        label: "MQTT" },
  { value: "modbus_tcp",  label: "Modbus TCP" },
  { value: "modbus_rtu",  label: "Modbus RTU" },
  { value: "snmp",        label: "SNMP" },
  { value: "bacnet",      label: "BACnet" },
  { value: "http",        label: "HTTP Poll" },
]

// ── Props ─────────────────────────────────────────────────────────────────────

interface Props {
  siteId: string
  sensor: SensorDevice | null  // null = add mode
  open: boolean
  onClose: () => void
  onSaved: (s: SensorDevice) => void
}

// ── Shared input / select class ───────────────────────────────────────────────

const inputCls =
  "border border-border rounded-md px-3 py-1.5 text-sm bg-background text-foreground w-full focus:outline-none focus:ring-1 focus:ring-primary"

// ── Protocol-specific config state types ──────────────────────────────────────

type MqttConfig      = { topic: string }
type ModbusTcpConfig = { host: string; port: number; unit_id: number }
type ModbusRtuConfig = { serial_port: string; baud_rate: number; unit_id: number }
type SnmpConfig      = { host: string; community: string; version: "v1" | "v2c" | "v3" }
type BacnetConfig    = { host: string; device_id: number }
type HttpConfig      = { url: string; poll_interval_s: number; json_path: string }

type ProtocolConfig =
  | MqttConfig
  | ModbusTcpConfig
  | ModbusRtuConfig
  | SnmpConfig
  | BacnetConfig
  | HttpConfig

function defaultProtocolConfig(protocol: Protocol): ProtocolConfig {
  switch (protocol) {
    case "mqtt":        return { topic: "" }
    case "modbus_tcp":  return { host: "", port: 502, unit_id: 1 }
    case "modbus_rtu":  return { serial_port: "", baud_rate: 9600, unit_id: 1 }
    case "snmp":        return { host: "", community: "public", version: "v2c" }
    case "bacnet":      return { host: "", device_id: 0 }
    case "http":        return { url: "", poll_interval_s: 30, json_path: "$.value" }
  }
}

function configFromSensor(sensor: SensorDevice): ProtocolConfig {
  const raw = sensor.protocol_config ?? {}
  switch (sensor.protocol) {
    case "mqtt":
      return { topic: (raw.topic as string) ?? "" }
    case "modbus_tcp":
      return {
        host:    (raw.host as string) ?? "",
        port:    (raw.port as number) ?? 502,
        unit_id: (raw.unit_id as number) ?? 1,
      }
    case "modbus_rtu":
      return {
        serial_port: (raw.serial_port as string) ?? "",
        baud_rate:   (raw.baud_rate as number) ?? 9600,
        unit_id:     (raw.unit_id as number) ?? 1,
      }
    case "snmp":
      return {
        host:      (raw.host as string) ?? "",
        community: (raw.community as string) ?? "public",
        version:   (raw.version as "v1" | "v2c" | "v3") ?? "v2c",
      }
    case "bacnet":
      return {
        host:      (raw.host as string) ?? "",
        device_id: (raw.device_id as number) ?? 0,
      }
    case "http":
      return {
        url:             (raw.url as string) ?? "",
        poll_interval_s: (raw.poll_interval_s as number) ?? 30,
        json_path:       (raw.json_path as string) ?? "$.value",
      }
  }
}

// ── Protocol-specific field editors ──────────────────────────────────────────

interface ConfigEditorProps<T> {
  config: T
  onChange: (next: T) => void
}

function MqttEditor({ config, onChange }: ConfigEditorProps<MqttConfig>) {
  return (
    <Field label="MQTT Topic">
      <input
        className={inputCls}
        value={config.topic}
        placeholder="sensors/site/device/metric"
        onChange={e => onChange({ ...config, topic: e.target.value })}
      />
    </Field>
  )
}

function ModbusTcpEditor({ config, onChange }: ConfigEditorProps<ModbusTcpConfig>) {
  return (
    <>
      <Field label="Host">
        <input
          className={inputCls}
          value={config.host}
          placeholder="192.168.1.10"
          onChange={e => onChange({ ...config, host: e.target.value })}
        />
      </Field>
      <Field label="Port">
        <input
          type="number"
          className={inputCls}
          value={config.port}
          onChange={e => onChange({ ...config, port: Number(e.target.value) })}
        />
      </Field>
      <Field label="Unit ID">
        <input
          type="number"
          className={inputCls}
          value={config.unit_id}
          onChange={e => onChange({ ...config, unit_id: Number(e.target.value) })}
        />
      </Field>
    </>
  )
}

function ModbusRtuEditor({ config, onChange }: ConfigEditorProps<ModbusRtuConfig>) {
  return (
    <>
      <Field label="Serial Port">
        <input
          className={inputCls}
          value={config.serial_port}
          placeholder="/dev/ttyUSB0"
          onChange={e => onChange({ ...config, serial_port: e.target.value })}
        />
      </Field>
      <Field label="Baud Rate">
        <input
          type="number"
          className={inputCls}
          value={config.baud_rate}
          onChange={e => onChange({ ...config, baud_rate: Number(e.target.value) })}
        />
      </Field>
      <Field label="Unit ID">
        <input
          type="number"
          className={inputCls}
          value={config.unit_id}
          onChange={e => onChange({ ...config, unit_id: Number(e.target.value) })}
        />
      </Field>
    </>
  )
}

function SnmpEditor({ config, onChange }: ConfigEditorProps<SnmpConfig>) {
  return (
    <>
      <Field label="Host">
        <input
          className={inputCls}
          value={config.host}
          placeholder="192.168.1.20"
          onChange={e => onChange({ ...config, host: e.target.value })}
        />
      </Field>
      <Field label="Community">
        <input
          className={inputCls}
          value={config.community}
          placeholder="public"
          onChange={e => onChange({ ...config, community: e.target.value })}
        />
      </Field>
      <Field label="Version">
        <select
          className={inputCls}
          value={config.version}
          onChange={e => onChange({ ...config, version: e.target.value as "v1" | "v2c" | "v3" })}
        >
          <option value="v1">v1</option>
          <option value="v2c">v2c</option>
          <option value="v3">v3</option>
        </select>
      </Field>
    </>
  )
}

function BacnetEditor({ config, onChange }: ConfigEditorProps<BacnetConfig>) {
  return (
    <>
      <Field label="Host">
        <input
          className={inputCls}
          value={config.host}
          placeholder="192.168.1.30"
          onChange={e => onChange({ ...config, host: e.target.value })}
        />
      </Field>
      <Field label="Device ID">
        <input
          type="number"
          className={inputCls}
          value={config.device_id}
          onChange={e => onChange({ ...config, device_id: Number(e.target.value) })}
        />
      </Field>
    </>
  )
}

function HttpEditor({ config, onChange }: ConfigEditorProps<HttpConfig>) {
  return (
    <>
      <Field label="URL">
        <input
          className={inputCls}
          value={config.url}
          placeholder="http://device/api/status"
          onChange={e => onChange({ ...config, url: e.target.value })}
        />
      </Field>
      <Field label="Poll Interval (seconds)">
        <input
          type="number"
          className={inputCls}
          value={config.poll_interval_s}
          onChange={e => onChange({ ...config, poll_interval_s: Number(e.target.value) })}
        />
      </Field>
      <Field label="JSON Path">
        <input
          className={inputCls}
          value={config.json_path}
          placeholder="$.value"
          onChange={e => onChange({ ...config, json_path: e.target.value })}
        />
      </Field>
    </>
  )
}

// ── Reusable field wrapper ────────────────────────────────────────────────────

function Field({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <div className="flex flex-col gap-1">
      <span className="text-xs text-muted-foreground">{label}</span>
      {children}
    </div>
  )
}

// ── Toggle switch ─────────────────────────────────────────────────────────────

function Toggle({
  checked,
  onChange,
}: {
  checked: boolean
  onChange: (v: boolean) => void
}) {
  return (
    <button
      type="button"
      role="switch"
      aria-checked={checked}
      onClick={() => onChange(!checked)}
      className={cn(
        "relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2",
        checked ? "bg-primary" : "bg-muted"
      )}
    >
      <span
        className={cn(
          "pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow-sm transition-transform",
          checked ? "translate-x-4" : "translate-x-0"
        )}
      />
    </button>
  )
}

// ── Main component ────────────────────────────────────────────────────────────

export function SensorSheet({ siteId, sensor, open, onClose, onSaved }: Props) {
  const isEdit = sensor !== null

  // ── Form state ────────────────────────────────────────────────────────────
  const [deviceId,   setDeviceId]   = useState("")
  const [name,       setName]       = useState("")
  const [deviceType, setDeviceType] = useState<DeviceType>("ups")
  const [room,       setRoom]       = useState("")
  const [enabled,    setEnabled]    = useState(true)
  const [protocol,   setProtocol]   = useState<Protocol>("mqtt")
  const [protoConfig, setProtoConfig] = useState<ProtocolConfig>(defaultProtocolConfig("mqtt"))

  const [saving, setSaving] = useState(false)
  const [error,  setError]  = useState<string | null>(null)

  // ── Populate form when sheet opens / sensor changes ───────────────────────
  useEffect(() => {
    if (!open) return
    setError(null)
    setSaving(false)
    if (sensor) {
      setDeviceId(sensor.device_id)
      setName(sensor.name)
      setDeviceType(sensor.device_type)
      setRoom(sensor.room_id ?? "")
      setEnabled(sensor.enabled)
      setProtocol(sensor.protocol)
      setProtoConfig(configFromSensor(sensor))
    } else {
      setDeviceId("")
      setName("")
      setDeviceType("ups")
      setRoom("")
      setEnabled(true)
      setProtocol("mqtt")
      setProtoConfig(defaultProtocolConfig("mqtt"))
    }
  }, [open, sensor])

  // ── Protocol change — reset config to defaults ────────────────────────────
  function handleProtocolChange(p: Protocol) {
    setProtocol(p)
    setProtoConfig(defaultProtocolConfig(p))
  }

  // ── Submit ────────────────────────────────────────────────────────────────
  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault()
    setError(null)
    setSaving(true)
    try {
      const body: SensorCreate = {
        device_id:       deviceId.trim(),
        name:            name.trim(),
        device_type:     deviceType,
        room_id:         room.trim() || null,
        protocol,
        protocol_config: protoConfig as Record<string, unknown>,
        enabled,
      }
      const saved = isEdit
        ? await updateSensor(sensor!.id, body)
        : await createSensor(siteId, body)
      onSaved(saved)
    } catch (err) {
      setError(err instanceof Error ? err.message : "Save failed")
    } finally {
      setSaving(false)
    }
  }

  // ── Protocol config editor ────────────────────────────────────────────────
  function renderProtoFields() {
    switch (protocol) {
      case "mqtt":
        return (
          <MqttEditor
            config={protoConfig as MqttConfig}
            onChange={c => setProtoConfig(c)}
          />
        )
      case "modbus_tcp":
        return (
          <ModbusTcpEditor
            config={protoConfig as ModbusTcpConfig}
            onChange={c => setProtoConfig(c)}
          />
        )
      case "modbus_rtu":
        return (
          <ModbusRtuEditor
            config={protoConfig as ModbusRtuConfig}
            onChange={c => setProtoConfig(c)}
          />
        )
      case "snmp":
        return (
          <SnmpEditor
            config={protoConfig as SnmpConfig}
            onChange={c => setProtoConfig(c)}
          />
        )
      case "bacnet":
        return (
          <BacnetEditor
            config={protoConfig as BacnetConfig}
            onChange={c => setProtoConfig(c)}
          />
        )
      case "http":
        return (
          <HttpEditor
            config={protoConfig as HttpConfig}
            onChange={c => setProtoConfig(c)}
          />
        )
    }
  }

  // ── Render ────────────────────────────────────────────────────────────────
  return (
    <Sheet open={open} onOpenChange={v => { if (!v) onClose() }}>
      <SheetContent side="right" className="w-full sm:max-w-md flex flex-col overflow-y-auto">
        <SheetHeader className="px-6 pt-6 pb-2">
          <SheetTitle>{isEdit ? "Edit Sensor" : "Add Sensor"}</SheetTitle>
        </SheetHeader>

        <form onSubmit={handleSubmit} className="flex flex-col flex-1 px-6 pb-6 gap-5">
          {/* ── Device ID ── */}
          <Field label="Device ID *">
            <input
              className={cn(inputCls, isEdit && "opacity-60 cursor-not-allowed")}
              value={deviceId}
              required
              disabled={isEdit}
              placeholder="ups-01"
              onChange={e => setDeviceId(e.target.value)}
            />
          </Field>

          {/* ── Name ── */}
          <Field label="Name *">
            <input
              className={inputCls}
              value={name}
              required
              placeholder="Main UPS — Hall A"
              onChange={e => setName(e.target.value)}
            />
          </Field>

          {/* ── Device Type ── */}
          <Field label="Device Type">
            <select
              className={inputCls}
              value={deviceType}
              onChange={e => setDeviceType(e.target.value as DeviceType)}
            >
              {DEVICE_TYPE_OPTIONS.map(o => (
                <option key={o.value} value={o.value}>{o.label}</option>
              ))}
            </select>
          </Field>

          {/* ── Room ── */}
          <Field label="Room (optional)">
            <input
              className={inputCls}
              value={room}
              placeholder="hall-a"
              onChange={e => setRoom(e.target.value)}
            />
          </Field>

          {/* ── Enabled toggle ── */}
          <div className="flex items-center justify-between">
            <span className="text-xs text-muted-foreground">Enabled</span>
            <Toggle checked={enabled} onChange={setEnabled} />
          </div>

          {/* ── Divider ── */}
          <hr className="border-border" />

          {/* ── Protocol ── */}
          <Field label="Protocol">
            <select
              className={inputCls}
              value={protocol}
              onChange={e => handleProtocolChange(e.target.value as Protocol)}
            >
              {PROTOCOL_OPTIONS.map(o => (
                <option key={o.value} value={o.value}>{o.label}</option>
              ))}
            </select>
          </Field>

          {/* ── Protocol-specific fields ── */}
          {renderProtoFields()}

          {/* ── Non-MQTT collector notice ── */}
          {protocol !== "mqtt" && (
            <div className="flex gap-2 rounded-md border border-border bg-muted/40 p-3 text-xs text-muted-foreground">
              <Info className="mt-0.5 size-3.5 shrink-0 text-primary" />
              <span>
                Protocol config stored — active polling not yet implemented.
                Data will appear once the collector is enabled.
              </span>
            </div>
          )}

          {/* ── Error ── */}
          {error && (
            <p className="text-xs text-destructive">{error}</p>
          )}

          {/* ── Actions ── */}
          <div className="mt-auto flex gap-2 pt-2">
            <Button
              type="button"
              variant="outline"
              className="flex-1"
              onClick={onClose}
              disabled={saving}
            >
              Cancel
            </Button>
            <Button type="submit" className="flex-1" disabled={saving}>
              {saving && <Loader2 className="animate-spin" />}
              {saving ? "Saving…" : isEdit ? "Save Changes" : "Add Sensor"}
            </Button>
          </div>
        </form>
      </SheetContent>
    </Sheet>
  )
}
