"use client";

import { useCallback } from "react";

import { useChatToolStore, type ChatToolAction } from "@/store/chatToolStore";
import type { StreamEvent } from "@/lib/chatStream";
import type { AgentArtifact, AgentArtifactKind } from "../GlobalChatbox.types";
import {
  APPLY_LAYER_STYLE_TOOL,
  describeApplyLayerStyle,
  parseApplyLayerStylePayload,
} from "../toolCallStyleHelpers";

type ToolCallEvent = StreamEvent & { type: "tool_call" };

type HandleToolCallOptions = {
  assistantMessageId: string;
  appendArtifact: (messageId: string, artifact: AgentArtifact) => void;
};

const FEATURE_TYPE_MAP: Record<
  string,
  { layer: string; geometryKind: "point" | "line"; label: string }
> = {
  junction: { layer: "geo_junctions_mat", geometryKind: "point", label: "节点" },
  junctions: { layer: "geo_junctions_mat", geometryKind: "point", label: "节点" },
  pipe: { layer: "geo_pipes_mat", geometryKind: "line", label: "管道" },
  pipes: { layer: "geo_pipes_mat", geometryKind: "line", label: "管道" },
  valve: { layer: "geo_valves", geometryKind: "point", label: "阀门" },
  valves: { layer: "geo_valves", geometryKind: "point", label: "阀门" },
  reservoir: { layer: "geo_reservoirs", geometryKind: "point", label: "水源" },
  reservoirs: { layer: "geo_reservoirs", geometryKind: "point", label: "水源" },
  pump: { layer: "geo_pumps", geometryKind: "point", label: "泵站" },
  pumps: { layer: "geo_pumps", geometryKind: "point", label: "泵站" },
  tank: { layer: "geo_tanks", geometryKind: "point", label: "水池" },
  tanks: { layer: "geo_tanks", geometryKind: "point", label: "水池" },
};

const LOCATE_TOOL_CONFIG: Record<
  string,
  { layer: string; geometryKind: "point" | "line"; label: string }
> = {
  locate_pipes: { layer: "geo_pipes_mat", geometryKind: "line", label: "管道" },
  locate_junctions: { layer: "geo_junctions_mat", geometryKind: "point", label: "节点" },
  locate_valves: { layer: "geo_valves", geometryKind: "point", label: "阀门" },
  locate_reservoirs: { layer: "geo_reservoirs", geometryKind: "point", label: "水源" },
  locate_pumps: { layer: "geo_pumps", geometryKind: "point", label: "泵站" },
  locate_tanks: { layer: "geo_tanks", geometryKind: "point", label: "水池" },
};

const LOCATE_ID_PARAM_KEYS = [
  "ids",
  "id",
  "feature_ids",
  "feature_id",
  "node_ids",
  "node_id",
  "junction_ids",
  "junction_id",
  "pipe_ids",
  "pipe_id",
  "valve_ids",
  "valve_id",
  "reservoir_ids",
  "reservoir_id",
  "pump_ids",
  "pump_id",
  "tank_ids",
  "tank_id",
] as const;

const normalizeIds = (params: Record<string, unknown>): string[] => {
  for (const key of LOCATE_ID_PARAM_KEYS) {
    const rawValue = params[key];
    if (Array.isArray(rawValue)) {
      const normalized = rawValue.map((id) => String(id).trim()).filter(Boolean);
      if (normalized.length > 0) {
        return normalized;
      }
    }
    if (typeof rawValue === "string" || typeof rawValue === "number") {
      const normalized = String(rawValue)
        .split(",")
        .map((id) => id.trim())
        .filter(Boolean);
      if (normalized.length > 0) {
        return normalized;
      }
    }
  }
  return [];
};

const resolveScadaFeatureInfos = (params: Record<string, unknown>): [string, string][] => {
  const rawFeatureInfos = params.feature_infos;
  if (Array.isArray(rawFeatureInfos)) {
    const normalizedFeatureInfos = rawFeatureInfos
      .map((item) => (Array.isArray(item) ? item : null))
      .filter((item): item is [unknown, unknown] => Boolean(item))
      .map(
        (item) =>
          [String(item[0] ?? ""), String(item[1] ?? "scada")] as [
            string,
            string,
          ],
      )
      .filter(([id]) => id.trim().length > 0);
    if (normalizedFeatureInfos.length > 0) {
      return normalizedFeatureInfos;
    }
  }

  const rawDeviceIds =
    params.device_ids ??
    params.deviceId ??
    params.device_id ??
    params.id ??
    params.ids;
  const deviceIds = Array.isArray(rawDeviceIds)
    ? rawDeviceIds.map((id) => String(id))
    : typeof rawDeviceIds === "string"
      ? rawDeviceIds
          .split(",")
          .map((id) => id.trim())
          .filter(Boolean)
      : [];

  return deviceIds.map((id) => [id, "scada"]);
};

const resolveTimeRange = (params: Record<string, unknown>) => ({
  startTime:
    (params.start_time as string | undefined) ??
    (params.startTime as string | undefined) ??
    (params.from as string | undefined) ??
    (params.start as string | undefined),
  endTime:
    (params.end_time as string | undefined) ??
    (params.endTime as string | undefined) ??
    (params.to as string | undefined) ??
    (params.end as string | undefined),
});

const compactNames = (names: string[]) => {
  if (!names.length) return "";
  return names.length > 3
    ? `${names.slice(0, 3).join(", ")} 等 ${names.length} 个`
    : names.join(", ");
};

const readFiniteNumber = (value: unknown): number | null => {
  if (typeof value === "number" && Number.isFinite(value)) {
    return value;
  }
  if (typeof value === "string" && value.trim()) {
    const parsed = Number(value);
    return Number.isFinite(parsed) ? parsed : null;
  }
  return null;
};

const parseZoomTo3857Action = (
  params: Record<string, unknown>,
): Extract<ChatToolAction, { type: "zoom_to_map" }> | null => {
  const rawCoordinate = params.coordinate ?? params.coordinates ?? params.center;
  const tuple = Array.isArray(rawCoordinate)
    ? rawCoordinate
    : [params.x ?? params.lon ?? params.longitude, params.y ?? params.lat ?? params.latitude];
  const x = readFiniteNumber(tuple[0]);
  const y = readFiniteNumber(tuple[1]);
  if (x === null || y === null) {
    return null;
  }

  const zoom = readFiniteNumber(params.zoom);
  const durationMs = readFiniteNumber(params.duration_ms ?? params.durationMs);
  const rawSourceCrs = params.source_crs ?? params.sourceCrs ?? params.crs;
  const normalizedSourceCrs =
    typeof rawSourceCrs === "string" ? rawSourceCrs.trim().toUpperCase() : "";
  const sourceCrs =
    normalizedSourceCrs === "EPSG:4326" ? "EPSG:4326" : "EPSG:3857";
  return {
    type: "zoom_to_map",
    coordinate: [x, y],
    sourceCrs,
    zoom: zoom ?? undefined,
    durationMs: durationMs ?? undefined,
  };
};

const buildLocateArtifact = (
  tool: string,
  params: Record<string, unknown>,
): { artifact: Omit<AgentArtifact, "id" | "params" | "tool">; action: ChatToolAction | null } => {
  const ids = normalizeIds(params);
  const rawType = params.feature_type;
  const featureType =
    typeof rawType === "string" ? rawType.trim().toLowerCase() : "";
  const config = tool === "locate_features"
    ? FEATURE_TYPE_MAP[featureType]
    : LOCATE_TOOL_CONFIG[tool];

  return {
    artifact: {
      kind: "map",
      title: config ? `地图定位${config.label}` : "地图定位",
      description: compactNames(ids),
    },
    action: config
      ? {
          type: "locate_features",
          ids,
          layer: config.layer,
          geometryKind: config.geometryKind,
        }
      : null,
  };
};

const buildToolAction = (
  tool: string,
  params: Record<string, unknown>,
): { action: ChatToolAction | null; kind: AgentArtifactKind; title: string; description?: string } => {
  if (tool === "show_chart") {
    return {
      action: null,
      kind: "chart",
      title: (params.title as string | undefined) ?? "生成图表",
      description: "已生成可视化图表",
    };
  }

  if (tool === "zoom_to_map") {
    const action = parseZoomTo3857Action(params);
    return {
      action,
      kind: "map",
      title: "缩放到地图坐标",
      description: action
        ? `${action.coordinate[0]}, ${action.coordinate[1]} (${action.sourceCrs})`
        : "地图坐标",
    };
  }

  if (tool === "locate_features" || LOCATE_TOOL_CONFIG[tool]) {
    const locate = buildLocateArtifact(tool, params);
    return {
      action: locate.action,
      kind: locate.artifact.kind,
      title: locate.artifact.title,
      description: locate.artifact.description,
    };
  }

  if (tool === "view_history") {
    const featureInfos = (params.feature_infos as [string, string][] | undefined) ?? [];
    const { startTime, endTime } = resolveTimeRange(params);
    return {
      action: {
        type: "view_history",
        featureInfos,
        dataType:
          (params.data_type as "realtime" | "scheme" | "none" | undefined) ??
          "realtime",
        startTime,
        endTime,
      },
      kind: "panel",
      title: "打开计算结果曲线",
      description: compactNames(featureInfos.map(([id]) => id)),
    };
  }

  if (tool === "view_scada") {
    const featureInfos = resolveScadaFeatureInfos(params);
    const { startTime, endTime } = resolveTimeRange(params);
    return {
      action: {
        type: "view_scada",
        featureInfos,
        startTime,
        endTime,
      },
      kind: "panel",
      title: "打开 SCADA 数据面板",
      description: compactNames(featureInfos.map(([id]) => id)),
    };
  }

  if (tool === "render_junctions") {
    const renderRef =
      typeof params.render_ref === "string" ? params.render_ref.trim() : "";

    return {
      action: renderRef
        ? {
            type: "render_junctions",
            renderRef,
            sessionId: undefined,
          }
        : null,
      kind: "map",
      title: "渲染节点分区",
      description: renderRef || "渲染引用",
    };
  }

  if (tool === APPLY_LAYER_STYLE_TOOL) {
    const payload = parseApplyLayerStylePayload(params);
    return {
      action: payload
        ? {
            type: "apply_layer_style",
            layerId: payload.layerId,
            resetToDefault: payload.resetToDefault,
            styleConfig: payload.styleConfig,
          }
        : null,
      kind: "map",
      title: payload?.resetToDefault ? "重置图层样式" : "应用图层样式",
      description: payload ? describeApplyLayerStyle(payload) : "图层样式",
    };
  }

  return {
    action: null,
    kind: "tool",
    title: tool || "工具调用",
    description: "Agent 已执行工具动作",
  };
};

export const useAgentToolActions = () => {
  const dispatchToolAction = useChatToolStore((s) => s.dispatch);

  return useCallback(
    (event: ToolCallEvent, options: HandleToolCallOptions) => {
      const { action, kind, title, description } = buildToolAction(
        event.tool,
        event.params,
      );

      const normalizedAction =
        action?.type === "render_junctions"
          ? { ...action, sessionId: event.sessionId }
          : action;

      options.appendArtifact(options.assistantMessageId, {
        id: `${event.tool}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
        tool: event.tool,
        kind,
        title,
        description,
        params: event.params,
      });

      if (normalizedAction) {
        dispatchToolAction(normalizedAction);
      }
    },
    [dispatchToolAction],
  );
};
