import { useEffect, useMemo, useState } from "react";
import { ChevronDown, Crosshair, LocateFixed, RotateCcw, X } from "lucide-react";
import { cn } from "@/shared/ui/cn";
import {
  LAYER_GROUP_GEOMETRIES,
  type LayerGroupId,
  type LayerGroupStylePatch
} from "../map/layer-group-style";
import { MAP_STYLE_TOKENS } from "../map/map-colors";
import { getNumericFeatureProperties } from "../map/value-label";
import type {
  FeatureTarget,
  WorkbenchMapCommands,
  WorkbenchMapControllerState
} from "../map/workbench-map-controller";
import { AVAILABLE_WATER_NETWORK_SOURCE_IDS, type AvailableWaterNetworkSourceId } from "../map/sources";
import type { DetailFeature } from "../types";

type MapDevPanelProps = {
  commands: WorkbenchMapCommands;
  controllerState: WorkbenchMapControllerState;
  detailFeature: DetailFeature | null;
  onClose: () => void;
};

const GROUP_LABELS: Record<AvailableWaterNetworkSourceId, string> = {
  pipes: "管线",
  junctions: "节点",
  valves: "阀门",
  reservoirs: "水库",
  scada: "SCADA"
};

const STYLE_GROUP_IDS = Object.keys(LAYER_GROUP_GEOMETRIES) as LayerGroupId[];

const ERROR_LABELS: Record<string, string> = {
  MAP_NOT_READY: "地图尚未就绪",
  FEATURE_NOT_FOUND: "目标要素不存在",
  WFS_UNAVAILABLE: "WFS 查询暂不可用",
  FLOW_UNAVAILABLE: "水流图层初始化失败",
  INVALID_STYLE_PATCH: "参数不符合受控范围"
};

export function MapDevPanel({ commands, controllerState, detailFeature, onClose }: MapDevPanelProps) {
  const [sourceId, setSourceId] = useState<AvailableWaterNetworkSourceId>("pipes");
  const [featureId, setFeatureId] = useState("DWS30265WS2010031117");
  const [property, setProperty] = useState("diameter");
  const [precision, setPrecision] = useState(0);
  const [unit, setUnit] = useState("mm");
  const [groupId, setGroupId] = useState<LayerGroupId>("pipes");
  const [draft, setDraft] = useState<Record<string, string | number>>({
    color: MAP_STYLE_TOKENS.supply.pipeMedium,
    fillColor: MAP_STYLE_TOKENS.supply.junction,
    strokeColor: "#FFFFFF",
    opacity: 0.9,
    widthMultiplier: 1,
    radiusMultiplier: 1,
    strokeMultiplier: 1,
    iconMultiplier: 1,
    dash: "original"
  });

  useEffect(() => {
    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") onClose();
    };
    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [onClose]);

  const numericProperties = useMemo(
    () => detailFeature && detailFeature.layer === sourceId && detailFeature.id === featureId
      ? getNumericFeatureProperties(detailFeature.properties)
      : [],
    [detailFeature, featureId, sourceId]
  );
  const target: FeatureTarget = { sourceId, featureId: featureId.trim() };
  const geometry = LAYER_GROUP_GEOMETRIES[groupId];

  function useSelectedFeature() {
    if (!detailFeature) return;
    if (AVAILABLE_WATER_NETWORK_SOURCE_IDS.includes(detailFeature.layer as AvailableWaterNetworkSourceId)) {
      setSourceId(detailFeature.layer as AvailableWaterNetworkSourceId);
    }
    setFeatureId(detailFeature.id);
    const firstNumeric = getNumericFeatureProperties(detailFeature.properties)[0];
    if (firstNumeric) setProperty(firstNumeric[0]);
  }

  function applyDraft() {
    let patch: LayerGroupStylePatch;
    if (geometry === "line") {
      patch = {
        color: String(draft.color),
        opacity: Number(draft.opacity),
        widthMultiplier: Number(draft.widthMultiplier),
        dash: draft.dash as "original" | "solid" | "dashed"
      };
    } else {
      patch = {
        fillColor: String(draft.fillColor),
        strokeColor: String(draft.strokeColor),
        opacity: Number(draft.opacity),
        radiusMultiplier: Number(draft.radiusMultiplier),
        strokeMultiplier: Number(draft.strokeMultiplier),
      };
    }
    commands.applyLayerGroupStyle(groupId, patch);
  }

  return (
    <aside
      aria-label="地图开发面板"
      className="acrylic-panel pointer-events-auto absolute right-3 top-[4.5rem] z-40 hidden max-h-[calc(100dvh-5.5rem)] w-[400px] flex-col overflow-hidden rounded-2xl border border-white/70 shadow-2xl lg:flex"
      data-testid="map-dev-panel"
    >
      <div className="flex h-12 shrink-0 items-center justify-between border-b border-slate-200/70 px-4">
        <div>
          <h2 className="text-sm font-semibold text-slate-950">地图能力 Dev Panel</h2>
          <p className="text-[11px] text-slate-500">仅本次页面会话生效</p>
        </div>
        <button className="grid h-8 w-8 place-items-center rounded-lg text-slate-500 transition hover:bg-white/70 hover:text-slate-900 active:scale-95" type="button" aria-label="关闭 Dev Panel" onClick={onClose}>
          <X size={16} />
        </button>
      </div>

      <div className="min-h-0 flex-1 space-y-3 overflow-y-auto p-3">
        {controllerState.errorCode ? (
          <div role="alert" className="rounded-xl border border-red-200 bg-red-50/90 px-3 py-2 text-xs font-medium text-red-700">
            {ERROR_LABELS[controllerState.errorCode] ?? controllerState.errorCode}
          </div>
        ) : null}

        <PanelSection title="Feature" description="WFS 验证后执行独立高亮或相机定位。">
          <div className="grid grid-cols-[120px_1fr] gap-2">
            <Field label="业务源">
              <select value={sourceId} onChange={(event) => setSourceId(event.target.value as AvailableWaterNetworkSourceId)} className={inputClassName}>
                {AVAILABLE_WATER_NETWORK_SOURCE_IDS.map((id) => <option key={id} value={id}>{GROUP_LABELS[id]}</option>)}
              </select>
            </Field>
            <Field label="Feature ID">
              <input value={featureId} onChange={(event) => setFeatureId(event.target.value)} className={inputClassName} />
            </Field>
          </div>
          <button type="button" disabled={!detailFeature} onClick={useSelectedFeature} className={secondaryButtonClassName}>使用当前地图选中</button>
          <div className="grid grid-cols-2 gap-2">
            <button type="button" disabled={!target.featureId || controllerState.pending} onClick={() => void commands.highlight(target)} className={primaryButtonClassName}><Crosshair size={14} />仅高亮</button>
            <button type="button" disabled={!target.featureId || controllerState.pending} onClick={() => void commands.locateAndHighlight(target)} className={primaryButtonClassName}><LocateFixed size={14} />定位并高亮</button>
          </div>
          <button type="button" onClick={commands.clearHighlight} className={secondaryButtonClassName}>清除高亮</button>
        </PanelSection>

        <PanelSection title="全网水流" description="按管线拓扑方向显示静态或动画流纹。">
          <div className="grid grid-cols-2 gap-2">
            <button type="button" disabled={controllerState.pending || controllerState.flowVisible} onClick={() => void commands.setFlowVisible(true)} className={primaryButtonClassName}>开启水流</button>
            <button type="button" disabled={!controllerState.flowVisible} onClick={() => void commands.setFlowVisible(false)} className={secondaryButtonClassName}>关闭水流</button>
          </div>
        </PanelSection>

        <PanelSection title="数值标注" description="仅为当前测试目标显示一个数值属性。">
          <Field label="数值属性">
            {numericProperties.length ? (
              <select value={property} onChange={(event) => setProperty(event.target.value)} className={inputClassName}>
                {numericProperties.map(([key]) => <option key={key} value={key}>{key}</option>)}
              </select>
            ) : <input value={property} onChange={(event) => setProperty(event.target.value)} className={inputClassName} />}
          </Field>
          <div className="grid grid-cols-2 gap-2">
            <Field label="精度 0-3"><input type="number" min={0} max={3} value={precision} onChange={(event) => setPrecision(Number(event.target.value))} className={inputClassName} /></Field>
            <Field label="单位"><input maxLength={16} value={unit} onChange={(event) => setUnit(event.target.value)} className={inputClassName} /></Field>
          </div>
          <div className="grid grid-cols-2 gap-2">
            <button type="button" disabled={!target.featureId || !property || controllerState.pending} onClick={() => void commands.showValueLabel({ target, property, precision, unit })} className={primaryButtonClassName}>显示标注</button>
            <button type="button" onClick={commands.clearValueLabel} className={secondaryButtonClassName}>清除标注</button>
          </div>
        </PanelSection>

        <PanelSection title="样式编辑" description="覆盖业务组样式，交互语义色保持不变。">
          <Field label="业务图层组">
            <div className="relative">
              <select value={groupId} onChange={(event) => setGroupId(event.target.value as LayerGroupId)} className={cn(inputClassName, "appearance-none pr-8")}>
                {STYLE_GROUP_IDS.map((id) => <option key={id} value={id}>{GROUP_LABELS[id]}</option>)}
              </select>
              <ChevronDown size={14} className="pointer-events-none absolute right-2.5 top-2.5 text-slate-400" />
            </div>
          </Field>
          {geometry === "line" ? (
            <>
              <ColorField label="颜色" value={String(draft.color)} onChange={(value) => setDraft((current) => ({ ...current, color: value }))} />
              <RangeField label="透明度" min={0} max={1} step={0.05} value={Number(draft.opacity)} onChange={(value) => setDraft((current) => ({ ...current, opacity: value }))} />
              <RangeField label="宽度倍率" min={0.5} max={3} step={0.1} value={Number(draft.widthMultiplier)} onChange={(value) => setDraft((current) => ({ ...current, widthMultiplier: value }))} />
              <Field label="线型"><select value={draft.dash} onChange={(event) => setDraft((current) => ({ ...current, dash: event.target.value }))} className={inputClassName}><option value="original">原始</option><option value="solid">实线</option><option value="dashed">虚线</option></select></Field>
            </>
          ) : (
            <>
              <div className="grid grid-cols-2 gap-2"><ColorField label="填充" value={String(draft.fillColor)} onChange={(value) => setDraft((current) => ({ ...current, fillColor: value }))} /><ColorField label="描边" value={String(draft.strokeColor)} onChange={(value) => setDraft((current) => ({ ...current, strokeColor: value }))} /></div>
              <RangeField label="透明度" min={0} max={1} step={0.05} value={Number(draft.opacity)} onChange={(value) => setDraft((current) => ({ ...current, opacity: value }))} />
              <RangeField label="半径倍率" min={0.5} max={3} step={0.1} value={Number(draft.radiusMultiplier)} onChange={(value) => setDraft((current) => ({ ...current, radiusMultiplier: value }))} />
              <RangeField label="描边倍率" min={0.5} max={3} step={0.1} value={Number(draft.strokeMultiplier)} onChange={(value) => setDraft((current) => ({ ...current, strokeMultiplier: value }))} />
            </>
          )}
          <div className="grid grid-cols-2 gap-2">
            <button type="button" onClick={applyDraft} className={primaryButtonClassName}>应用</button>
            <button type="button" onClick={() => commands.resetLayerGroupStyle(groupId)} className={secondaryButtonClassName}>重置本组</button>
          </div>
        </PanelSection>
      </div>

      <div className="shrink-0 border-t border-slate-200/70 p-3">
        <button type="button" onClick={commands.resetAll} className={cn(secondaryButtonClassName, "w-full")}><RotateCcw size={14} />重置全部</button>
      </div>
    </aside>
  );
}

function PanelSection({ title, description, children }: { title: string; description: string; children: React.ReactNode }) {
  return <section className="space-y-2.5 border-b border-slate-200/70 px-1 pb-4 last:border-b-0 last:pb-1"><div><h3 className="text-xs font-semibold text-slate-900">{title}</h3><p className="mt-0.5 text-[11px] leading-4 text-slate-500">{description}</p></div>{children}</section>;
}

function Field({ label, children }: { label: string; children: React.ReactNode }) {
  return <label className="block min-w-0"><span className="mb-1 block text-[11px] font-medium text-slate-600">{label}</span>{children}</label>;
}

function ColorField({ label, value, onChange }: { label: string; value: string; onChange: (value: string) => void }) {
  return <Field label={label}><div className="flex h-9 items-center gap-2 rounded-lg border border-slate-200 bg-white/80 px-2"><input type="color" value={value} onChange={(event) => onChange(event.target.value.toUpperCase())} className="h-5 w-7 cursor-pointer border-0 bg-transparent p-0" /><span className="text-xs font-medium text-slate-600">{value}</span></div></Field>;
}

function RangeField({ label, min, max, step, value, onChange }: { label: string; min: number; max: number; step: number; value: number; onChange: (value: number) => void }) {
  return <Field label={`${label} · ${value}`}><input aria-label={label} type="range" min={min} max={max} step={step} value={value} onChange={(event) => onChange(Number(event.target.value))} className="h-6 w-full accent-blue-600" /></Field>;
}

const inputClassName = "h-9 w-full rounded-lg border border-slate-200 bg-white/80 px-2.5 text-xs text-slate-800 outline-hidden transition focus:border-blue-400 focus:ring-2 focus:ring-blue-500/15";
const primaryButtonClassName = "inline-flex h-9 items-center justify-center gap-1.5 rounded-lg bg-blue-600 px-3 text-xs font-semibold text-white transition hover:bg-blue-700 active:scale-95 disabled:cursor-not-allowed disabled:scale-100 disabled:opacity-45";
const secondaryButtonClassName = "inline-flex h-9 items-center justify-center gap-1.5 rounded-lg border border-slate-200 bg-white/70 px-3 text-xs font-semibold text-slate-700 transition hover:bg-white active:scale-95 disabled:cursor-not-allowed disabled:scale-100 disabled:opacity-45";
