import { useEffect, useState } from "react";
import { ChevronDown, Crosshair, RotateCcw, X, ZoomIn } from "lucide-react";
import { Button } from "@/shared/ui/button";
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 LABEL_PRESETS: Record<
  LayerGroupId,
  {
    property: string;
    precision: number;
    unit: string;
    options: { value: string; label: string }[];
  }
> = {
  pipes: {
    property: "diameter",
    precision: 0,
    unit: "mm",
    options: [
      { value: "diameter", label: "管径 diameter" },
      { value: "length", label: "长度 length" },
      { value: "roughness", label: "粗糙系数 roughness" },
      { value: "minor_loss", label: "局部损失 minor_loss" }
    ]
  },
  junctions: {
    property: "elevation",
    precision: 1,
    unit: "m",
    options: [
      { value: "elevation", label: "高程 elevation" },
      { value: "demand", label: "需水量 demand" }
    ]
  },
  valves: {
    property: "diameter",
    precision: 0,
    unit: "mm",
    options: [
      { value: "diameter", label: "管径 diameter" },
      { value: "setting", label: "设定值 setting" },
      { value: "minor_loss", label: "局部损失 minor_loss" }
    ]
  },
  reservoirs: {
    property: "head",
    precision: 1,
    unit: "m",
    options: [{ value: "head", label: "水头 head" }]
  }
};

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

export function MapDevPanel({
  commands,
  controllerState,
  detailFeature,
  onClose
}: MapDevPanelProps) {
  const [sourceId, setSourceId] = useState<AvailableWaterNetworkSourceId>("pipes");
  const [featureId, setFeatureId] = useState("440681");
  const [property, setProperty] = useState("diameter");
  const [flowPipeId, setFlowPipeId] = useState("440681");
  const [flowVelocity, setFlowVelocity] = useState("-1");
  const [precision, setPrecision] = useState(0);
  const [unit, setUnit] = useState("mm");
  const [groupId, setGroupId] = useState<LayerGroupId>("pipes");
  const [showValueLabels, setShowValueLabels] = useState(true);
  const [showFeatureIds, setShowFeatureIds] = useState(false);
  const [labelSize, setLabelSize] = useState(12);
  const [labelColor, setLabelColor] = useState<string>(MAP_STYLE_TOKENS.label.primary);
  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 target: FeatureTarget = { sourceId, featureId: featureId.trim() };
  const geometry = LAYER_GROUP_GEOMETRIES[groupId];
  const activeLabel = controllerState.valueLabels[groupId];
  const hasActiveLabels = Object.keys(controllerState.valueLabels).length > 0;

  function selectStyleGroup(nextGroupId: LayerGroupId) {
    const preset = LABEL_PRESETS[nextGroupId];
    const saved = controllerState.valueLabels[nextGroupId];
    setGroupId(nextGroupId);
    setProperty(saved?.property ?? preset.property);
    setPrecision(saved?.precision ?? preset.precision);
    setUnit(saved?.unit ?? preset.unit);
    setShowValueLabels(saved?.showValue ?? true);
    setShowFeatureIds(saved?.showId ?? false);
    setLabelSize(saved?.textSize ?? 12);
    setLabelColor(saved?.textColor ?? MAP_STYLE_TOKENS.label.primary);
  }

  function useSelectedFeature() {
    if (!detailFeature) return;
    if (
      AVAILABLE_WATER_NETWORK_SOURCE_IDS.includes(
        detailFeature.layer as AvailableWaterNetworkSourceId
      )
    ) {
      setSourceId(detailFeature.layer as AvailableWaterNetworkSourceId);
    }
    setFeatureId(detailFeature.id);
    if (detailFeature.layer === "pipes") setFlowPipeId(detailFeature.id);
    if (detailFeature.layer in LAYER_GROUP_GEOMETRIES) {
      const nextGroupId = detailFeature.layer as LayerGroupId;
      selectStyleGroup(nextGroupId);
      const allowedProperties = new Set(
        LABEL_PRESETS[nextGroupId].options.map((option) => option.value)
      );
      const firstNumeric = getNumericFeatureProperties(detailFeature.properties).find(
        ([name]) => allowedProperties.has(name)
      );
      if (firstNumeric) setProperty(firstNumeric[0]);
    }
  }

  function applyLayerStyle() {
    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),
        iconMultiplier: Number(draft.iconMultiplier)
      };
    }
    commands.applyLayerGroupStyle(groupId, patch);
  }

  function applyLabels() {
    if (showValueLabels || showFeatureIds) {
      void commands.showValueLabel({
        sourceId: groupId,
        property,
        precision,
        unit,
        showValue: showValueLabels,
        showId: showFeatureIds,
        textSize: labelSize,
        textColor: labelColor
      });
    } else {
      commands.clearValueLabel(groupId);
    }
  }

  function applyFlowCalculation() {
    commands.updatePipeFlowCalculation({
      pipeId: flowPipeId.trim(),
      velocity: Number(flowVelocity)
    });
  }

  const flowSummary = controllerState.flowSummary;
  const validFlowCalculation =
    flowPipeId.trim().length > 0 && Number.isFinite(Number(flowVelocity));

  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 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
          size="icon"
          variant="ghost"
          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="status-tone-danger rounded-xl border border-[var(--status-border)] bg-[var(--status-soft)] px-3 py-2 text-xs font-medium text-[var(--status-foreground)]"
          >
            {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);
                  setFeatureId("");
                }}
                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="w-full text-xs"
            variant="outline"
          >
            使用当前地图选中
          </Button>
          <div className="grid grid-cols-2 gap-2">
            <Button
              type="button"
              disabled={!target.featureId || controllerState.pending}
              onClick={() => void commands.highlight(target)}
              className="w-full text-xs"
            >
              <Crosshair size={14} />
              仅高亮
            </Button>
            <Button
              type="button"
              disabled={!target.featureId || controllerState.pending}
              onClick={() => void commands.zoomToFeature(target)}
              className="w-full text-xs"
            >
              <ZoomIn size={14} />
              缩放到 Feature
            </Button>
          </div>
          <Button
            type="button"
            disabled={!target.featureId || controllerState.pending}
            onClick={() => void commands.locateAndHighlight(target)}
            className="w-full text-xs"
            variant="outline"
          >
            定位并高亮
          </Button>
          <Button
            type="button"
            onClick={() => commands.clearHighlight()}
            className="w-full text-xs"
            variant="outline"
          >
            清除高亮
          </Button>
          {controllerState.target ? (
            <StatusText>
              已高亮 {controllerState.target.sourceId}:{controllerState.target.featureId}
            </StatusText>
          ) : null}
        </PanelSection>

        <PanelSection
          title="全网水流"
          description="开启时为全部管道生成正反向 mock；有符号流速可覆盖单管方向。"
        >
          <div className="grid grid-cols-2 gap-2">
            <Button
              type="button"
              disabled={controllerState.pending || controllerState.flowVisible}
              onClick={() => void commands.setFlowVisible(true)}
              className="w-full text-xs"
            >
              开启水流
            </Button>
            <Button
              type="button"
              disabled={!controllerState.flowVisible}
              onClick={() => void commands.setFlowVisible(false)}
              className="w-full text-xs"
              variant="outline"
            >
              关闭水流
            </Button>
          </div>
          <div className="grid grid-cols-2 gap-2">
            <Field label="管道 ID">
              <input
                value={flowPipeId}
                onChange={(event) => setFlowPipeId(event.target.value)}
                className={inputClassName}
              />
            </Field>
            <Field label="有符号流速">
              <input
                type="number"
                step="any"
                value={flowVelocity}
                onChange={(event) => setFlowVelocity(event.target.value)}
                className={inputClassName}
              />
            </Field>
          </div>
          <Button
            type="button"
            disabled={!validFlowCalculation || controllerState.pending}
            onClick={applyFlowCalculation}
            className="w-full text-xs"
          >
            更新该管道方向
          </Button>
          <div className="grid grid-cols-2 gap-2">
            <Button
              type="button"
              disabled={sourceId !== "pipes" || !target.featureId}
              onClick={() => setFlowPipeId(target.featureId)}
              className="w-full text-xs"
              variant="outline"
            >
              使用 Feature ID
            </Button>
            <Button
              type="button"
              onClick={() => void commands.clearPipeFlowCalculations()}
              className="w-full text-xs"
              variant="outline"
            >
              清空流速
            </Button>
          </div>
          {flowSummary.total > 0 ? (
            <StatusText>
              全网 mock · 已赋值 {flowSummary.total} · 正向 {flowSummary.forward} · 反向{" "}
              {flowSummary.reverse} · 停止 {flowSummary.stopped}
            </StatusText>
          ) : controllerState.flowVisible ? (
            <StatusText>全网 mock 已启用 · 正反向交错显示</StatusText>
          ) : (
            <StatusText>开启后自动显示全网 mock 流向</StatusText>
          )}
        </PanelSection>

        <PanelSection
          title="样式编辑"
          description="统一配置业务几何与整层 MVT 标注，交互语义色保持不变。"
        >
          <Field label="业务图层组">
            <div className="relative">
              <select
                value={groupId}
                onChange={(event) => selectStyleGroup(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 }))
                }
              />
              {groupId !== "junctions" ? (
                <RangeField
                  label="图标倍率"
                  min={0.5}
                  max={3}
                  step={0.1}
                  value={Number(draft.iconMultiplier)}
                  onChange={(value) =>
                    setDraft((current) => ({ ...current, iconMultiplier: value }))
                  }
                />
              ) : null}
            </>
          )}
          <div className="space-y-2.5 rounded-xl bg-slate-100/75 p-3 shadow-[inset_0_0_0_1px_rgba(148,163,184,0.18)]">
            <div className="flex items-start justify-between gap-3">
              <div>
                <h4 className="text-[11px] font-semibold text-slate-800">整层标注</h4>
                <p className="mt-0.5 text-[10px] leading-4 text-slate-500">
                  作用于当前图层所有可见 Feature，自动避让重叠。
                </p>
              </div>
              <span className="shrink-0 rounded-md bg-teal-50 px-1.5 py-0.5 text-[9px] font-semibold text-teal-700">
                MVT 原生
              </span>
            </div>
            <div className="grid grid-cols-2 gap-2">
              <ToggleField label="数值" checked={showValueLabels} onChange={setShowValueLabels} />
              <ToggleField label="设施 ID" checked={showFeatureIds} onChange={setShowFeatureIds} />
            </div>
            {showValueLabels ? (
              <>
                <Field label="数值属性">
                  <select
                    value={property}
                    onChange={(event) => setProperty(event.target.value)}
                    className={inputClassName}
                  >
                    {LABEL_PRESETS[groupId].options.map((option) => (
                      <option key={option.value} value={option.value}>
                        {option.label}
                      </option>
                    ))}
                  </select>
                </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>
              </>
            ) : null}
            <RangeField
              label="字号"
              min={10}
              max={18}
              step={1}
              value={labelSize}
              onChange={setLabelSize}
            />
            <ColorField label="文字颜色" value={labelColor} onChange={setLabelColor} />
            <div className="grid grid-cols-2 gap-2">
              <Button
                type="button"
                disabled={!showValueLabels && !showFeatureIds}
                onClick={applyLabels}
                className="w-full text-xs"
              >
                应用标注
              </Button>
              <Button
                type="button"
                disabled={!hasActiveLabels}
                onClick={() => {
                  setShowValueLabels(false);
                  setShowFeatureIds(false);
                  commands.clearValueLabel();
                }}
                className="w-full text-xs"
                variant="outline"
              >
                清除全部标注
              </Button>
            </div>
            {activeLabel ? (
              <StatusText>
                已标注全部 {GROUP_LABELS[groupId]} Feature · {activeLabel.showId ? "ID + " : ""}
                {activeLabel.showValue ? activeLabel.property : "仅 ID"}
              </StatusText>
            ) : null}
          </div>
          <div className="grid grid-cols-2 gap-2">
            <Button type="button" onClick={applyLayerStyle} className="w-full text-xs">
              应用图层样式
            </Button>
            <Button
              type="button"
              onClick={() => commands.resetLayerGroupStyle(groupId)}
              className="w-full text-xs"
              variant="outline"
            >
              重置本组
            </Button>
          </div>
          {controllerState.styledGroups.includes(groupId) ? (
            <StatusText>已覆盖当前图层组样式</StatusText>
          ) : null}
        </PanelSection>
      </div>

      <div className="shrink-0 border-t border-slate-200/70 p-3">
        <Button
          type="button"
          onClick={() => commands.resetAll()}
          className="w-full text-xs"
          variant="outline"
        >
          <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 ToggleField({
  label,
  checked,
  onChange
}: {
  label: string;
  checked: boolean;
  onChange: (checked: boolean) => void;
}) {
  return (
    <label className="flex h-9 cursor-pointer items-center gap-2 rounded-lg bg-white/80 px-2.5 text-[11px] font-medium text-slate-700 shadow-[inset_0_0_0_1px_rgba(203,213,225,0.9)]">
      <input
        type="checkbox"
        checked={checked}
        onChange={(event) => onChange(event.target.checked)}
        className="h-4 w-4 accent-blue-600"
      />
      {label}
    </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>
  );
}

function StatusText({ children }: { children: React.ReactNode }) {
  return (
    <p
      role="status"
      className="status-tone-success rounded-lg border border-[var(--status-border)] bg-[var(--status-soft)] px-2.5 py-1.5 text-[11px] font-medium text-[var(--status-foreground)]"
    >
      {children}
    </p>
  );
}

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";
