import { app, ipcMain, shell } from "electron";
import path from "node:path";
import type {
  AssistantChatRequest,
  AssistantChatResponse,
  AssistantIntentRequest,
  AssistantIntentResponse,
  AssistantRunRequest,
  DashboardSnapshot,
  LoginRequest,
  PriceComparisonExportRequest,
  TableExportRequest,
  TaskRunRequest
} from "../../shared/types";
import type { AgentRunner } from "../agent/runner";
import { listTasks } from "../agent/tasks";
import type { SmqjhClient } from "../cloud/smqjhClient";
import type { SessionState } from "../cloud/session";
import type { ConfigStore } from "../config/appConfig";
import type { DeepSeekClient } from "../deepseek/deepSeekClient";
import { exportPriceComparisonWorkbook } from "../exports/priceComparisonExport";
import { exportTablesWorkbook } from "../exports/tableExport";
import type { LogStore } from "../agent/logStore";
import type { AssistantOrchestrator } from "../assistant/assistantOrchestrator";
import type { McpClient } from "../mcp/mcpClient";

export function registerIpc(deps: {
  configStore: ConfigStore;
  logStore: LogStore;
  runner: AgentRunner;
  client: SmqjhClient;
  session: SessionState;
  deepSeekClient: DeepSeekClient;
  assistantOrchestrator: AssistantOrchestrator;
  mcpClient: McpClient;
}): void {
  ipcMain.handle("config:get", async () => deps.configStore.get());
  ipcMain.handle("config:save", async (_event, patch) => deps.configStore.save(patch));

  ipcMain.handle("dashboard:get", async (): Promise<DashboardSnapshot> => {
    await deps.client.ensureSessionFresh();
    return {
      config: deps.configStore.get(),
      session: deps.session.status(),
      taskCount: listTasks().length,
      lastLogs: deps.logStore.list().slice(0, 8)
    };
  });

  ipcMain.handle("tasks:list", async () => listTasks());
  ipcMain.handle("tasks:run", async (_event, request: TaskRunRequest) => deps.runner.run(request));

  ipcMain.handle("logs:list", async () => deps.logStore.list());
  ipcMain.handle("logs:clear", async () => deps.logStore.clear());

  ipcMain.handle("session:login", async (_event, request: LoginRequest) => {
    try {
      const result = await deps.client.login(request);
      if (!result.ok) {
        throw new Error(result.message);
      }
      deps.logStore.add("success", `后台账号 ${request.username} 已登录`);
      return deps.session.status();
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      deps.logStore.add("error", `后台账号 ${request.username} 登录失败：${message}`);
      throw new Error(message);
    }
  });

  ipcMain.handle("session:logout", async () => deps.client.logout());
  ipcMain.handle("session:get", async () => {
    await deps.client.ensureSessionFresh();
    return deps.session.status();
  });

  ipcMain.handle("auth:captcha", async () => {
    const result = await deps.client.getCaptcha();
    if (!result.ok || !result.data) {
      throw new Error(result.message || "验证码获取失败");
    }
    return result.data;
  });

  ipcMain.handle("mcp:config:get", async () => {
    try {
      const result = await deps.mcpClient.callTool("smqjh.config.get", {});
      deps.logStore.add("info", "MCP 配置状态读取完成");
      return result.structuredContent ?? {};
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      deps.logStore.add("error", `MCP 配置状态读取失败：${message}`);
      throw new Error(message);
    }
  });

  ipcMain.handle("assistant:chat", async (_event, request: AssistantChatRequest) => {
    try {
      const mcpResult = await deps.mcpClient.callTool("smqjh.ai.chat", {
        request: {
          ...request,
          message: "",
          history: request.messages
        }
      });
      const result = asRecord(mcpResult.structuredContent) as unknown as AssistantChatResponse;
      deps.logStore.add("info", "MCP DeepSeek 对话完成", { model: result.model });
      return result;
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      deps.logStore.add("error", `MCP DeepSeek 对话失败：${message}`);
      throw new Error(message);
    }
  });

  ipcMain.handle("assistant:intent", async (_event, request: AssistantIntentRequest) => {
    try {
      const mcpResult = await deps.mcpClient.callTool("smqjh.ai.tool.plan", {
        request: {
          message: request.message,
          history: request.history,
          authenticated: request.authenticated,
          username: request.username,
          environmentName: request.environmentName,
          baseUrl: request.baseUrl
        },
        tools: request.availableTasks.map((task) => ({
          name: task.id,
          source: "local",
          title: task.title,
          description: task.description,
          inputSchema: {
            type: "object",
            properties: {},
            additionalProperties: true
          }
        }))
      });
      const record = asRecord(mcpResult.structuredContent);
      const firstCall = Array.isArray(record.toolCalls) ? asRecord(record.toolCalls[0]) : {};
      const taskId = typeof firstCall.name === "string" ? normalizeMcpToolName(firstCall.name) : undefined;
      const result: AssistantIntentResponse = {
        taskId,
        confidence: taskId ? 0.75 : 0,
        params: stringifyParams(asRecord(firstCall.arguments)),
        reason: typeof record.reason === "string" ? record.reason : undefined,
        model: typeof record.model === "string" ? record.model : "mcp-deepseek"
      };
      deps.logStore.add("info", "MCP DeepSeek 意图识别完成", { model: result.model, taskId: result.taskId, confidence: result.confidence });
      return result;
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      deps.logStore.add("error", `MCP DeepSeek 意图识别失败：${message}`);
      throw new Error(message);
    }
  });

  ipcMain.handle("assistant:run", async (_event, request: AssistantRunRequest) => {
    try {
      const result = await deps.assistantOrchestrator.run(request);
      deps.logStore.add("info", "智能体工具编排完成", {
        model: result.model,
        usedMcp: result.usedMcp,
        toolCount: result.toolCalls.length
      });
      return result;
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      deps.logStore.add("error", `智能体工具编排失败：${message}`);
      throw new Error(message);
    }
  });

  ipcMain.handle("exports:price-comparison", async (_event, request: PriceComparisonExportRequest) => {
    try {
      const result = await exportPriceComparisonWorkbook(request, app.getPath("downloads"));
      deps.logStore.add("success", "价格对比 Excel 已导出", {
        fileName: result.fileName,
        rowCount: result.rowCount
      });
      return result;
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      deps.logStore.add("error", `价格对比 Excel 导出失败：${message}`);
      throw new Error(message);
    }
  });

  ipcMain.handle("exports:tables", async (_event, request: TableExportRequest) => {
    try {
      const result = await exportTablesWorkbook(request, app.getPath("downloads"));
      deps.logStore.add("success", "智能体表格 Excel 已导出", {
        fileName: result.fileName,
        tableCount: result.tableCount,
        rowCount: result.rowCount
      });
      return result;
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      deps.logStore.add("error", `智能体表格 Excel 导出失败：${message}`);
      throw new Error(message);
    }
  });

  ipcMain.handle("exports:open-file", async (_event, filePath: string) => {
    const exportPath = assertExportPath(filePath);
    const message = await shell.openPath(exportPath);
    if (message) {
      throw new Error(message);
    }
  });

  ipcMain.handle("exports:show-file", async (_event, filePath: string) => {
    const exportPath = assertExportPath(filePath);
    shell.showItemInFolder(exportPath);
  });
}

function assertExportPath(filePath: string): string {
  const downloadsDir = path.resolve(app.getPath("downloads"));
  const resolved = path.resolve(String(filePath || ""));
  const relative = path.relative(downloadsDir, resolved);
  if (!resolved.toLowerCase().endsWith(".xlsx") || relative.startsWith("..") || path.isAbsolute(relative)) {
    throw new Error("只能打开由助手导出的 Excel 文件");
  }
  return resolved;
}

function asRecord(value: unknown): Record<string, unknown> {
  return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : {};
}

function stringifyParams(params: Record<string, unknown>): Record<string, string> {
  return Object.fromEntries(
    Object.entries(params).map(([key, value]) => [key, value === undefined || value === null ? "" : String(value)])
  );
}

function normalizeMcpToolName(name: string): string {
  if (name === "smqjh.product.price.compare") {
    return "product.price.compare";
  }
  if (name.startsWith("smqjh.")) {
    return name.slice("smqjh.".length);
  }
  return name;
}
