import { createProductierClient, ProductierApiError } from "./client.mjs";
import {
  createAuditLogger,
  createRateLimiter,
  createRuntimeConfig,
  invokeWithRetry,
  ToolRateLimitError,
  unwrapInvocationError
} from "./runtime-hardening.mjs";
import { createConnectMailboxTool } from "./tool-connect-mailbox.mjs";
import { createCreateBoardGroupTool } from "./tool-create-board-group.mjs";
import { createCreateCalendarEventTool } from "./tool-create-calendar-event.mjs";
import { createCreateOutgoingMailTool } from "./tool-create-outgoing-mail.mjs";
import { createCreateTaskFromMailTool } from "./tool-create-task-from-mail.mjs";
import { createCreateNoteTool } from "./tool-create-note.mjs";
import { createCreateTaskTool } from "./tool-create-task.mjs";
import { createListBoardGroupsTool } from "./tool-list-board-groups.mjs";
import { createListCalendarEventsTool } from "./tool-list-calendar-events.mjs";
import { createListMailboxesTool } from "./tool-list-mailboxes.mjs";
import { createListMailMessagesTool } from "./tool-list-mail-messages.mjs";
import { createListNotesTool } from "./tool-list-notes.mjs";
import { createListOutgoingMailsTool } from "./tool-list-outgoing-mails.mjs";
import { createListTasksTool } from "./tool-list-tasks.mjs";
import { createListWorkspacesTool } from "./tool-list-workspaces.mjs";
import { createSyncMailboxTool } from "./tool-sync-mailbox.mjs";
import { createUpdateBoardGroupTool } from "./tool-update-board-group.mjs";
import { createUpdateCalendarEventTool } from "./tool-update-calendar-event.mjs";
import { createUpdateNoteTool } from "./tool-update-note.mjs";
import { createUpdateTaskTool } from "./tool-update-task.mjs";

export const pluginManifest = {
  name: "productier-openclaw",
  version: "0.1.0",
  description: "OpenClaw tool plugin for Productier workspace operations.",
  profiles: {
    readonly: {
      tools: ["productier_list_workspaces", "productier_list_tasks"]
    },
    standard: {
      tools: [
        "productier_list_workspaces",
        "productier_list_board_groups",
        "productier_list_tasks",
        "productier_list_calendar_events",
        "productier_list_notes",
        "productier_list_mailboxes",
        "productier_list_mail_messages",
        "productier_list_outgoing_mails",
        "productier_connect_mailbox",
        "productier_sync_mailbox",
        "productier_create_board_group",
        "productier_create_task",
        "productier_create_calendar_event",
        "productier_create_note",
        "productier_create_outgoing_mail",
        "productier_create_task_from_mail",
        "productier_update_board_group",
        "productier_update_task",
        "productier_update_calendar_event",
        "productier_update_note"
      ]
    }
  }
};

export function createPlugin(options = {}) {
  const profile = options.profile || process.env.PRODUCTIER_TOOL_PROFILE || "readonly";
  if (profile !== "readonly" && profile !== "standard") {
    throw new Error(`unsupported profile: ${profile}`);
  }

  const runtimeConfig = createRuntimeConfig(options);
  const rateLimiter = createRateLimiter(runtimeConfig.rateLimit, options);
  const auditLogger = createAuditLogger(options, runtimeConfig);
  const client = createProductierClient(options);
  const listWorkspaces = createListWorkspacesTool(client);
  const listBoardGroups = createListBoardGroupsTool(client, options);
  const listTasks = createListTasksTool(client, options);
  const listCalendarEvents = createListCalendarEventsTool(client, options);
  const listNotes = createListNotesTool(client, options);
  const listMailboxes = createListMailboxesTool(client, options);
  const listMailMessages = createListMailMessagesTool(client, options);
  const listOutgoingMails = createListOutgoingMailsTool(client, options);
  const connectMailbox = createConnectMailboxTool(client, options);
  const syncMailbox = createSyncMailboxTool(client);
  const createBoardGroup = createCreateBoardGroupTool(client, options);
  const createTask = createCreateTaskTool(client, options);
  const createCalendarEvent = createCreateCalendarEventTool(client, options);
  const createNote = createCreateNoteTool(client, options);
  const createOutgoingMail = createCreateOutgoingMailTool(client, options);
  const createTaskFromMail = createCreateTaskFromMailTool(client, options);
  const updateBoardGroup = createUpdateBoardGroupTool(client);
  const updateTask = createUpdateTaskTool(client);
  const updateCalendarEvent = createUpdateCalendarEventTool(client);
  const updateNote = createUpdateNoteTool(client);

  const allTools = [
    listWorkspaces,
    listBoardGroups,
    listTasks,
    listCalendarEvents,
    listNotes,
    listMailboxes,
    listMailMessages,
    listOutgoingMails,
    connectMailbox,
    syncMailbox,
    createBoardGroup,
    createTask,
    createCalendarEvent,
    createNote,
    createOutgoingMail,
    createTaskFromMail,
    updateBoardGroup,
    updateTask,
    updateCalendarEvent,
    updateNote
  ];
  const enabledToolNames = new Set(pluginManifest.profiles[profile].tools);
  const tools = new Map(allTools.filter(tool => enabledToolNames.has(tool.name)).map(tool => [tool.name, tool]));

  return {
    manifest: pluginManifest,
    listTools() {
      return [...tools.values()].map(tool => ({
        name: tool.name,
        description: tool.description,
        inputSchema: tool.inputSchema
      }));
    },
    async runTool(name, input) {
      const tool = tools.get(name);
      if (!tool) {
        return {
          ok: false,
          error: {
            code: "tool_not_found",
            message: `Unknown tool: ${name}`
          }
        };
      }

      const startedAt = Date.now();
      const recordedInput = input || {};

      try {
        rateLimiter.consume(name);
        const { data, attempts } = await invokeWithRetry(
          () => tool.invoke(recordedInput),
          runtimeConfig.retry,
          options,
        );

        const result = {
          ok: true,
          data,
          meta: {
            attempts,
            durationMs: Date.now() - startedAt
          }
        };

        await auditLogger.log({
          timestamp: new Date().toISOString(),
          profile,
          tool: name,
          ok: true,
          attempts,
          durationMs: result.meta.durationMs,
          errorCode: null,
          requestId: null
        });

        return result;
      } catch (error) {
        const normalizedError = unwrapInvocationError(error);
        const cause = normalizedError.cause;
        const durationMs = Date.now() - startedAt;
        let result = null;

        if (cause instanceof ToolRateLimitError) {
          result = {
            ok: false,
            error: {
              code: cause.code,
              message: cause.message,
              status: cause.status,
              retryAfterMs: cause.retryAfterMs,
              retryable: false,
              attempts: normalizedError.attempts
            }
          };
        } else if (cause instanceof ProductierApiError) {
          result = {
            ok: false,
            error: {
              code: cause.code,
              message: cause.message,
              status: cause.status,
              requestId: cause.requestId,
              retryable: normalizedError.retryable,
              attempts: normalizedError.attempts
            }
          };
        } else {
          result = {
            ok: false,
            error: {
              code: "tool_execution_error",
              message: cause instanceof Error ? cause.message : "unknown error",
              retryable: normalizedError.retryable,
              attempts: normalizedError.attempts
            }
          };
        }

        await auditLogger.log({
          timestamp: new Date().toISOString(),
          profile,
          tool: name,
          ok: false,
          attempts: normalizedError.attempts,
          durationMs,
          errorCode: result.error.code,
          requestId: result.error.requestId ?? null,
          retryable: result.error.retryable ?? false
        });

        return result;
      }
    }
  };
}
