import { SystemRole } from "@capakraken/shared";
import type { TRPCContext } from "../../trpc.js";
import { withToolAccess, type ToolContext, type ToolDef, type ToolExecutor } from "./shared.js";

type AssistantToolErrorResult = { error: string };

type NotificationCategory = "NOTIFICATION" | "REMINDER" | "TASK" | "APPROVAL";
type NotificationPriority = "LOW" | "NORMAL" | "HIGH" | "URGENT";
type TaskStatus = "OPEN" | "IN_PROGRESS" | "DONE" | "DISMISSED";
type DeliveryChannel = "in_app" | "email" | "both";
type ReminderRecurrence = "daily" | "weekly" | "monthly";
type BroadcastTargetType = "user" | "role" | "project" | "orgUnit" | "all";

type NotificationRecord = {
  id: string;
};

type TaskRecord = {
  id: string;
  taskStatus?: TaskStatus | null;
};

type ReminderRecord = {
  id: string;
};

type BroadcastRecord = {
  id: string;
  recipientCount?: number | null;
};

type NotificationsTasksDeps = {
  createNotificationCaller: (ctx: TRPCContext) => {
    list: (params: { unreadOnly?: boolean; limit?: number }) => Promise<unknown>;
    markRead: (params: { id?: string }) => Promise<void>;
    unreadCount: () => Promise<number>;
    create: (params: {
      userId: string;
      type: string;
      title: string;
      body?: string;
      entityId?: string;
      entityType?: string;
      category?: NotificationCategory;
      priority?: NotificationPriority;
      link?: string;
      taskStatus?: TaskStatus;
      taskAction?: string;
      assigneeId?: string;
      dueDate?: Date;
      channel?: DeliveryChannel;
      senderId?: string;
    }) => Promise<NotificationRecord | null>;
    listTasks: (params: {
      status?: TaskStatus;
      includeAssigned?: boolean;
      limit?: number;
    }) => Promise<unknown>;
    taskCounts: () => Promise<unknown>;
    getTaskDetail: (params: { id: string }) => Promise<unknown>;
    updateTaskStatus: (params: { id: string; status: TaskStatus }) => Promise<TaskRecord>;
    executeTaskAction: (params: { id: string }) => Promise<{
      task: unknown;
      actionResult: { message: string };
    }>;
    createReminder: (params: {
      title: string;
      remindAt: Date;
      body?: string;
      recurrence?: ReminderRecurrence;
      entityId?: string;
      entityType?: string;
      link?: string;
    }) => Promise<ReminderRecord>;
    listReminders: (params: { limit?: number }) => Promise<unknown>;
    updateReminder: (params: {
      id: string;
      title?: string;
      body?: string;
      remindAt?: Date;
      recurrence?: ReminderRecurrence | null;
    }) => Promise<ReminderRecord>;
    deleteReminder: (params: { id: string }) => Promise<void>;
    createTask: (params: {
      userId: string;
      title: string;
      body?: string;
      priority?: NotificationPriority;
      dueDate?: Date;
      taskAction?: string;
      entityId?: string;
      entityType?: string;
      link?: string;
      channel?: DeliveryChannel;
    }) => Promise<TaskRecord | null>;
    assignTask: (params: { id: string; assigneeId: string }) => Promise<TaskRecord>;
    createBroadcast: (params: {
      title: string;
      targetType: BroadcastTargetType;
      body?: string;
      link?: string;
      category?: NotificationCategory;
      priority?: NotificationPriority;
      channel?: DeliveryChannel;
      targetValue?: string;
      scheduledAt?: Date;
      taskAction?: string;
      dueDate?: Date;
    }) => Promise<BroadcastRecord>;
    listBroadcasts: (params: { limit?: number }) => Promise<unknown>;
    getBroadcastById: (params: { id: string }) => Promise<unknown>;
    delete: (params: { id: string }) => Promise<void>;
  };
  createScopedCallerContext: (ctx: ToolContext) => TRPCContext;
  parseDateTime: (value: string, fieldName: string) => Date;
  parseOptionalDateTime: (value: string | undefined, fieldName: string) => Date | undefined;
  toAssistantTaskNotFoundError: (
    error: unknown,
  ) => AssistantToolErrorResult | null;
  toAssistantTaskActionError: (
    error: unknown,
  ) => AssistantToolErrorResult | null;
  toAssistantTaskAssignmentError: (
    error: unknown,
  ) => AssistantToolErrorResult | null;
  toAssistantBroadcastNotFoundError: (
    error: unknown,
  ) => AssistantToolErrorResult | null;
  toAssistantReminderNotFoundError: (
    error: unknown,
  ) => AssistantToolErrorResult | null;
  toAssistantNotificationReadError: (
    error: unknown,
  ) => AssistantToolErrorResult | null;
  toAssistantNotificationDeletionError: (
    error: unknown,
  ) => AssistantToolErrorResult | null;
  toAssistantReminderCreationError: (
    error: unknown,
  ) => AssistantToolErrorResult | null;
  toAssistantNotificationCreationError: (
    error: unknown,
    context: "notification" | "task" | "broadcast",
  ) => AssistantToolErrorResult | null;
};

export const notificationInboxToolDefinitions: ToolDef[] = withToolAccess([
  {
    type: "function",
    function: {
      name: "list_notifications",
      description: "List recent notifications for the current user.",
      parameters: {
        type: "object",
        properties: {
          unreadOnly: { type: "boolean", description: "Only show unread. Default: false" },
          limit: { type: "integer", description: "Max results. Default: 20" },
        },
      },
    },
  },
  {
    type: "function",
    function: {
      name: "mark_notification_read",
      description: "Mark one notification as read, or all unread notifications when no notificationId is provided. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          notificationId: { type: "string", description: "Notification ID. Omit to mark all unread notifications as read." },
        },
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_unread_notification_count",
      description: "Count unread notifications for the current user.",
      parameters: { type: "object", properties: {} },
    },
  },
  {
    type: "function",
    function: {
      name: "create_notification",
      description: "Create a notification or task-style notification for a specific user. Manager or admin role required. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          userId: { type: "string", description: "Target user ID." },
          type: { type: "string", description: "Notification type code." },
          title: { type: "string", description: "Title." },
          body: { type: "string", description: "Optional body text." },
          entityId: { type: "string", description: "Optional linked entity ID." },
          entityType: { type: "string", description: "Optional linked entity type." },
          category: { type: "string", enum: ["NOTIFICATION", "REMINDER", "TASK", "APPROVAL"] },
          priority: { type: "string", enum: ["LOW", "NORMAL", "HIGH", "URGENT"] },
          link: { type: "string", description: "Optional deep link." },
          taskStatus: { type: "string", enum: ["OPEN", "IN_PROGRESS", "DONE", "DISMISSED"] },
          taskAction: { type: "string", description: "Optional machine-readable task action." },
          assigneeId: { type: "string", description: "Optional assignee user ID." },
          dueDate: { type: "string", format: "date-time", description: "Optional due date." },
          channel: { type: "string", enum: ["in_app", "email", "both"] },
          senderId: { type: "string", description: "Optional sender override." },
        },
        required: ["userId", "type", "title"],
      },
    },
  },
], {
  create_notification: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER],
  },
});

export const notificationTaskToolDefinitions: ToolDef[] = withToolAccess([
  {
    type: "function",
    function: {
      name: "list_tasks",
      description: "List tasks and approvals for the current user via the real notification router, optionally including tasks assigned to them.",
      parameters: {
        type: "object",
        properties: {
          status: { type: "string", enum: ["OPEN", "IN_PROGRESS", "DONE", "DISMISSED"], description: "Optional task status filter" },
          includeAssigned: { type: "boolean", description: "Include tasks where the current user is assignee as well as owner. Default: true." },
          limit: { type: "integer", description: "Max results. Default: 20." },
        },
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_task_counts",
      description: "Get open, in-progress, done, dismissed, and overdue task counts for the current user.",
      parameters: { type: "object", properties: {} },
    },
  },
  {
    type: "function",
    function: {
      name: "get_task_detail",
      description: "Get details of a specific task/notification including linked entity information.",
      parameters: {
        type: "object",
        properties: {
          taskId: { type: "string", description: "Notification/task ID" },
        },
        required: ["taskId"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "update_task_status",
      description: "Update the status of a task. Mark as IN_PROGRESS, DONE, or DISMISSED.",
      parameters: {
        type: "object",
        properties: {
          taskId: { type: "string", description: "Task/notification ID" },
          status: { type: "string", enum: ["OPEN", "IN_PROGRESS", "DONE", "DISMISSED"], description: "New status" },
        },
        required: ["taskId", "status"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "execute_task_action",
      description: "Execute the machine-readable action associated with a task. For example: approve a vacation, confirm an assignment, etc. The action is encoded in the task's taskAction field.",
      parameters: {
        type: "object",
        properties: {
          taskId: { type: "string", description: "Task/notification ID containing the action to execute" },
        },
        required: ["taskId"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "create_reminder",
      description: "Create a personal reminder for the current user via the real notification router. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          title: { type: "string", description: "Reminder title" },
          body: { type: "string", description: "Optional details" },
          remindAt: { type: "string", format: "date-time", description: "When to remind (ISO 8601 datetime)" },
          recurrence: { type: "string", enum: ["daily", "weekly", "monthly"], description: "Optional recurrence pattern" },
          entityId: { type: "string", description: "Optional: linked entity ID (project, resource, etc.)" },
          entityType: { type: "string", description: "Optional: entity type (project, resource, vacation, etc.)" },
          link: { type: "string", description: "Optional deep link." },
        },
        required: ["title", "remindAt"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "list_reminders",
      description: "List personal reminders for the current user via the real notification router.",
      parameters: {
        type: "object",
        properties: {
          limit: { type: "integer", description: "Max results. Default: 20." },
        },
      },
    },
  },
  {
    type: "function",
    function: {
      name: "update_reminder",
      description: "Update a personal reminder via the real notification router. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          id: { type: "string", description: "Reminder notification ID." },
          title: { type: "string", description: "Optional reminder title." },
          body: { type: "string", description: "Optional reminder body." },
          remindAt: { type: "string", format: "date-time", description: "Optional reminder timestamp." },
          recurrence: { type: ["string", "null"], enum: ["daily", "weekly", "monthly", null], description: "Optional recurrence update. Use null to clear recurrence." },
        },
        required: ["id"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "delete_reminder",
      description: "Delete a personal reminder via the real notification router. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          id: { type: "string", description: "Reminder notification ID." },
        },
        required: ["id"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "create_task_for_user",
      description: "Create a task for a specific user via the real notification router. Manager or admin role required. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          userId: { type: "string", description: "Target user ID" },
          title: { type: "string", description: "Task title" },
          body: { type: "string", description: "Task description" },
          priority: { type: "string", enum: ["LOW", "NORMAL", "HIGH", "URGENT"], description: "Priority (default NORMAL)" },
          dueDate: { type: "string", format: "date-time", description: "Optional due date (ISO 8601)" },
          taskAction: { type: "string", description: "Optional machine-readable action (format: action_name:entity_id)" },
          entityId: { type: "string", description: "Optional linked entity ID" },
          entityType: { type: "string", description: "Optional entity type" },
          link: { type: "string", description: "Optional deep link." },
          channel: { type: "string", enum: ["in_app", "email", "both"], description: "Delivery channel. Default: in_app." },
        },
        required: ["userId", "title"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "assign_task",
      description: "Assign or reassign a task to another user via the real notification router. Manager or admin role required. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          id: { type: "string", description: "Task notification ID." },
          assigneeId: { type: "string", description: "User ID to assign." },
        },
        required: ["id", "assigneeId"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "send_broadcast",
      description: "Create and send a broadcast notification via the real notification router. Manager or admin role required. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          title: { type: "string", description: "Notification title" },
          body: { type: "string", description: "Notification body" },
          targetType: { type: "string", enum: ["user", "role", "project", "orgUnit", "all"], description: "Target audience type" },
          targetValue: { type: "string", description: "Target value: user ID, role name (ADMIN/MANAGER/CONTROLLER/USER/VIEWER), project ID, or org unit ID" },
          category: { type: "string", enum: ["NOTIFICATION", "REMINDER", "TASK", "APPROVAL"], description: "Broadcast category. Default: NOTIFICATION." },
          priority: { type: "string", enum: ["LOW", "NORMAL", "HIGH", "URGENT"], description: "Priority (default NORMAL)" },
          channel: { type: "string", enum: ["in_app", "email", "both"], description: "Delivery channel (default in_app)" },
          link: { type: "string", description: "Optional deep-link URL" },
          scheduledAt: { type: "string", format: "date-time", description: "Optional scheduled send timestamp." },
          taskAction: { type: "string", description: "Optional machine-readable task action for task-like broadcasts." },
          dueDate: { type: "string", format: "date-time", description: "Optional due date for task-like broadcasts." },
        },
        required: ["title", "targetType"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "list_broadcasts",
      description: "List notification broadcasts via the real notification router. Manager or admin role required.",
      parameters: {
        type: "object",
        properties: {
          limit: { type: "integer", description: "Max results. Default: 20." },
        },
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_broadcast_detail",
      description: "Get one notification broadcast via the real notification router. Manager or admin role required.",
      parameters: {
        type: "object",
        properties: {
          id: { type: "string", description: "Broadcast ID." },
        },
        required: ["id"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "delete_notification",
      description: "Delete one of the current user's own notifications via the real notification router. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          id: { type: "string", description: "Notification ID." },
        },
        required: ["id"],
      },
    },
  },
], {
  create_task_for_user: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER],
  },
  assign_task: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER],
  },
  send_broadcast: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER],
  },
  list_broadcasts: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER],
  },
  get_broadcast_detail: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER],
  },
});

export function createNotificationsTasksExecutors(
  deps: NotificationsTasksDeps,
): Record<string, ToolExecutor> {
  return {
    async list_notifications(params: { unreadOnly?: boolean; limit?: number }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      return caller.list({
        ...(params.unreadOnly !== undefined ? { unreadOnly: params.unreadOnly } : {}),
        ...(params.limit !== undefined ? { limit: Math.min(params.limit, 100) } : {}),
      });
    },

    async mark_notification_read(params: { notificationId?: string }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      try {
        await caller.markRead({
          ...(params.notificationId !== undefined ? { id: params.notificationId } : {}),
        });
      } catch (error) {
        const mapped = deps.toAssistantNotificationReadError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return {
        __action: "invalidate" as const,
        scope: ["notification"],
        success: true,
        message: params.notificationId ? "Notification marked as read." : "All unread notifications marked as read.",
      };
    },

    async get_unread_notification_count(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      const count = await caller.unreadCount();
      return { count };
    },

    async create_notification(params: {
      userId: string;
      type: string;
      title: string;
      body?: string;
      entityId?: string;
      entityType?: string;
      category?: NotificationCategory;
      priority?: NotificationPriority;
      link?: string;
      taskStatus?: TaskStatus;
      taskAction?: string;
      assigneeId?: string;
      dueDate?: string;
      channel?: DeliveryChannel;
      senderId?: string;
    }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      const dueDate = deps.parseOptionalDateTime(params.dueDate, "dueDate");

      let notification;
      try {
        notification = await caller.create({
          userId: params.userId,
          type: params.type,
          title: params.title,
          ...(params.body !== undefined ? { body: params.body } : {}),
          ...(params.entityId !== undefined ? { entityId: params.entityId } : {}),
          ...(params.entityType !== undefined ? { entityType: params.entityType } : {}),
          ...(params.category !== undefined ? { category: params.category } : {}),
          ...(params.priority !== undefined ? { priority: params.priority } : {}),
          ...(params.link !== undefined ? { link: params.link } : {}),
          ...(params.taskStatus !== undefined ? { taskStatus: params.taskStatus } : {}),
          ...(params.taskAction !== undefined ? { taskAction: params.taskAction } : {}),
          ...(params.assigneeId !== undefined ? { assigneeId: params.assigneeId } : {}),
          ...(dueDate ? { dueDate } : {}),
          ...(params.channel !== undefined ? { channel: params.channel } : {}),
          ...(params.senderId !== undefined ? { senderId: params.senderId } : {}),
        });
      } catch (error) {
        const mapped = deps.toAssistantNotificationCreationError(error, "notification");
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return {
        __action: "invalidate" as const,
        scope: ["notification"],
        success: true,
        notification,
        notificationId: notification?.id ?? null,
        message: `Created notification "${params.title}".`,
      };
    },

    async list_tasks(params: {
      status?: TaskStatus;
      includeAssigned?: boolean;
      limit?: number;
    }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      return caller.listTasks({
        ...(params.status !== undefined ? { status: params.status } : {}),
        ...(params.includeAssigned !== undefined ? { includeAssigned: params.includeAssigned } : {}),
        ...(params.limit !== undefined ? { limit: Math.min(params.limit, 100) } : {}),
      });
    },

    async get_task_counts(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      return caller.taskCounts();
    },

    async get_task_detail(params: { taskId: string }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      try {
        return await caller.getTaskDetail({ id: params.taskId });
      } catch (error) {
        const mapped = deps.toAssistantTaskNotFoundError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }
    },

    async update_task_status(params: { taskId: string; status: string }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));

      let task;
      try {
        task = await caller.updateTaskStatus({
          id: params.taskId,
          status: params.status as TaskStatus,
        });
      } catch (error) {
        const mapped = deps.toAssistantTaskNotFoundError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return {
        __action: "invalidate" as const,
        scope: ["notification"],
        success: true,
        task,
        message: `Task status updated to ${task.taskStatus ?? params.status}.`,
      };
    },

    async execute_task_action(params: { taskId: string }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));

      let result;
      try {
        result = await caller.executeTaskAction({ id: params.taskId });
      } catch (error) {
        const mapped = deps.toAssistantTaskActionError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return {
        __action: "invalidate" as const,
        scope: ["notification"],
        success: true,
        task: result.task,
        message: result.actionResult.message,
      };
    },

    async create_reminder(params: {
      title: string;
      body?: string;
      remindAt: string;
      recurrence?: string;
      entityId?: string;
      entityType?: string;
      link?: string;
    }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));

      if (!params.title.trim()) {
        return { error: "Reminder title is required." };
      }
      if (params.title.length > 200) {
        return { error: "Reminder title must be at most 200 characters." };
      }
      if (params.body !== undefined && params.body.length > 2000) {
        return { error: "Reminder body must be at most 2000 characters." };
      }
      if (
        params.recurrence !== undefined
        && !["daily", "weekly", "monthly"].includes(params.recurrence)
      ) {
        return {
          error: `Invalid recurrence: ${params.recurrence}. Valid values: daily, weekly, monthly.`,
        };
      }

      const remindAt = deps.parseDateTime(params.remindAt, "remindAt");

      let reminder;
      try {
        reminder = await caller.createReminder({
          title: params.title,
          remindAt,
          ...(params.body !== undefined ? { body: params.body } : {}),
          ...(params.recurrence !== undefined ? { recurrence: params.recurrence as ReminderRecurrence } : {}),
          ...(params.entityId !== undefined ? { entityId: params.entityId } : {}),
          ...(params.entityType !== undefined ? { entityType: params.entityType } : {}),
          ...(params.link !== undefined ? { link: params.link } : {}),
        });
      } catch (error) {
        const mapped = deps.toAssistantReminderCreationError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return {
        __action: "invalidate" as const,
        scope: ["notification"],
        success: true,
        reminder,
        reminderId: reminder.id,
        message: `Reminder "${params.title}" created.`,
      };
    },

    async list_reminders(params: { limit?: number }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      return caller.listReminders({
        ...(params.limit !== undefined ? { limit: Math.min(params.limit, 100) } : {}),
      });
    },

    async update_reminder(params: {
      id: string;
      title?: string;
      body?: string;
      remindAt?: string;
      recurrence?: ReminderRecurrence | null;
    }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      const remindAt = deps.parseOptionalDateTime(params.remindAt, "remindAt");

      let reminder;
      try {
        reminder = await caller.updateReminder({
          id: params.id,
          ...(params.title !== undefined ? { title: params.title } : {}),
          ...(params.body !== undefined ? { body: params.body } : {}),
          ...(remindAt ? { remindAt } : {}),
          ...(params.recurrence !== undefined ? { recurrence: params.recurrence } : {}),
        });
      } catch (error) {
        const mapped = deps.toAssistantReminderNotFoundError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return {
        __action: "invalidate" as const,
        scope: ["notification"],
        success: true,
        reminder,
        reminderId: reminder.id,
        message: `Updated reminder ${params.id}.`,
      };
    },

    async delete_reminder(params: { id: string }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      try {
        await caller.deleteReminder({ id: params.id });
      } catch (error) {
        const mapped = deps.toAssistantReminderNotFoundError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return {
        __action: "invalidate" as const,
        scope: ["notification"],
        success: true,
        id: params.id,
        message: `Deleted reminder ${params.id}.`,
      };
    },

    async create_task_for_user(params: {
      userId: string;
      title: string;
      body?: string;
      priority?: string;
      dueDate?: string;
      taskAction?: string;
      entityId?: string;
      entityType?: string;
      link?: string;
      channel?: DeliveryChannel;
    }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      const dueDate = deps.parseOptionalDateTime(params.dueDate, "dueDate");

      let task;
      try {
        task = await caller.createTask({
          userId: params.userId,
          title: params.title,
          ...(params.body !== undefined ? { body: params.body } : {}),
          ...(params.priority !== undefined ? { priority: params.priority as NotificationPriority } : {}),
          ...(dueDate ? { dueDate } : {}),
          ...(params.taskAction !== undefined ? { taskAction: params.taskAction } : {}),
          ...(params.entityId !== undefined ? { entityId: params.entityId } : {}),
          ...(params.entityType !== undefined ? { entityType: params.entityType } : {}),
          ...(params.link !== undefined ? { link: params.link } : {}),
          ...(params.channel !== undefined ? { channel: params.channel } : {}),
        });
      } catch (error) {
        const mapped = deps.toAssistantNotificationCreationError(error, "task");
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return {
        __action: "invalidate" as const,
        scope: ["notification"],
        success: true,
        task,
        taskId: task?.id ?? null,
        message: `Created task "${params.title}" for ${params.userId}.`,
      };
    },

    async assign_task(params: { id: string; assigneeId: string }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));

      let task;
      try {
        task = await caller.assignTask(params);
      } catch (error) {
        const mapped = deps.toAssistantTaskAssignmentError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return {
        __action: "invalidate" as const,
        scope: ["notification"],
        success: true,
        task,
        taskId: task.id,
        message: `Assigned task ${params.id} to ${params.assigneeId}.`,
      };
    },

    async send_broadcast(params: {
      title: string;
      body?: string;
      targetType: string;
      targetValue?: string;
      category?: NotificationCategory;
      priority?: string;
      channel?: string;
      link?: string;
      scheduledAt?: string;
      taskAction?: string;
      dueDate?: string;
    }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      const scheduledAt = deps.parseOptionalDateTime(params.scheduledAt, "scheduledAt");
      const dueDate = deps.parseOptionalDateTime(params.dueDate, "dueDate");

      let broadcast;
      try {
        broadcast = await caller.createBroadcast({
          title: params.title,
          targetType: params.targetType as BroadcastTargetType,
          ...(params.body !== undefined ? { body: params.body } : {}),
          ...(params.link !== undefined ? { link: params.link } : {}),
          ...(params.category !== undefined ? { category: params.category } : {}),
          ...(params.priority !== undefined ? { priority: params.priority as NotificationPriority } : {}),
          ...(params.channel !== undefined ? { channel: params.channel as DeliveryChannel } : {}),
          ...(params.targetValue !== undefined ? { targetValue: params.targetValue } : {}),
          ...(scheduledAt ? { scheduledAt } : {}),
          ...(params.taskAction !== undefined ? { taskAction: params.taskAction } : {}),
          ...(dueDate ? { dueDate } : {}),
        });
      } catch (error) {
        const mapped = deps.toAssistantNotificationCreationError(error, "broadcast");
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return {
        __action: "invalidate" as const,
        scope: ["notification"],
        success: true,
        broadcast,
        broadcastId: broadcast.id,
        recipientCount: broadcast.recipientCount ?? 0,
        message: `Broadcast "${params.title}" created.`,
      };
    },

    async list_broadcasts(params: { limit?: number }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      return caller.listBroadcasts({
        ...(params.limit !== undefined ? { limit: Math.min(params.limit, 50) } : {}),
      });
    },

    async get_broadcast_detail(params: { id: string }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      try {
        return await caller.getBroadcastById({ id: params.id });
      } catch (error) {
        const mapped = deps.toAssistantBroadcastNotFoundError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }
    },

    async delete_notification(params: { id: string }, ctx: ToolContext) {
      const caller = deps.createNotificationCaller(deps.createScopedCallerContext(ctx));
      try {
        await caller.delete({ id: params.id });
      } catch (error) {
        const mapped = deps.toAssistantNotificationDeletionError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return {
        __action: "invalidate" as const,
        scope: ["notification"],
        success: true,
        id: params.id,
        message: `Deleted notification ${params.id}.`,
      };
    },
  };
}
