/**
 * snow_assign_task - Universal task assignment
 *
 * Assign tasks to users or groups with workload balancing,
 * skill matching, and availability checking.
 */

import { type MCPToolDefinition, type ServiceNowContext, type ToolResult } from "../../shared/types.js"
import { getAuthenticatedClient } from "../../shared/auth.js"
import { createSuccessResult, createErrorResult, SnowFlowError, ErrorType } from "../../shared/error-handler.js"

export const toolDefinition: MCPToolDefinition = {
  name: "snow_assign_task",
  description: "Assign task to user or group with workload balancing and skill matching",
  // Metadata for tool discovery (not sent to LLM)
  category: "core-operations",
  subcategory: "task-management",
  use_cases: ["task-assignment", "workload"],
  complexity: "intermediate",
  frequency: "high",

  // Permission enforcement
  // Classification: WRITE - Write operation based on name pattern
  permission: "write",
  allowedRoles: ["developer", "admin"],
  inputSchema: {
    type: "object",
    properties: {
      table: {
        type: "string",
        description: "Task table (incident, change_request, sc_task, etc.)",
        default: "task",
      },
      sys_id: {
        type: "string",
        description: "Task sys_id or number",
      },
      assigned_to: {
        type: "string",
        description: "User sys_id or username to assign to",
      },
      assignment_group: {
        type: "string",
        description: "Group sys_id or name to assign to",
      },
      auto_assign: {
        type: "boolean",
        description: "Auto-assign to available group member with lowest workload",
        default: false,
      },
      check_availability: {
        type: "boolean",
        description: "Check user availability before assignment",
        default: false,
      },
      work_notes: {
        type: "string",
        description: "Work notes to add with assignment",
      },
    },
    required: ["sys_id"],
  },
}

export async function execute(args: any, context: ServiceNowContext): Promise<ToolResult> {
  const {
    table = "task",
    sys_id,
    assigned_to,
    assignment_group,
    auto_assign = false,
    check_availability = false,
    work_notes,
  } = args

  try {
    const client = await getAuthenticatedClient(context)

    // Get task
    let task
    if (sys_id.length === 32) {
      const response = await client.get(`/api/now/table/${table}/${sys_id}`, {
        params: { sysparm_fields: "sys_id,number,assigned_to,assignment_group" },
      })
      task = response.data.result
    } else {
      const response = await client.get(`/api/now/table/${table}`, {
        params: {
          sysparm_query: `number=${sys_id}`,
          sysparm_fields: "sys_id,number,assigned_to,assignment_group",
          sysparm_limit: 1,
        },
      })
      if (response.data.result && response.data.result.length > 0) {
        task = response.data.result[0]
      }
    }

    if (!task) {
      throw new SnowFlowError(ErrorType.NOT_FOUND_ERROR, `Task not found: ${sys_id}`, { details: { table, sys_id } })
    }

    const updateData: any = {}

    // Resolve assignment_group
    let resolvedGroupId
    if (assignment_group) {
      if (assignment_group.length === 32) {
        resolvedGroupId = assignment_group
      } else {
        const groupResponse = await client.get("/api/now/table/sys_user_group", {
          params: {
            sysparm_query: `name=${assignment_group}`,
            sysparm_fields: "sys_id,name",
            sysparm_limit: 1,
          },
        })
        if (groupResponse.data.result && groupResponse.data.result.length > 0) {
          resolvedGroupId = groupResponse.data.result[0].sys_id
        }
      }
      updateData.assignment_group = resolvedGroupId
    }

    // Handle user assignment
    if (assigned_to) {
      // Direct assignment
      if (assigned_to.length === 32) {
        updateData.assigned_to = assigned_to
      } else {
        const userResponse = await client.get("/api/now/table/sys_user", {
          params: {
            sysparm_query: `user_name=${assigned_to}`,
            sysparm_fields: "sys_id,user_name,active",
            sysparm_limit: 1,
          },
        })
        if (userResponse.data.result && userResponse.data.result.length > 0) {
          const user = userResponse.data.result[0]
          if (!user.active) {
            throw new SnowFlowError(
              ErrorType.VALIDATION_ERROR,
              `User '${assigned_to}' is inactive and cannot be assigned tasks`,
              { details: { user: assigned_to } },
            )
          }
          updateData.assigned_to = user.sys_id
        }
      }

      // Check availability if requested
      if (check_availability && updateData.assigned_to) {
        const scheduleResponse = await client.get("/api/now/table/cmn_schedule", {
          params: {
            sysparm_query: `type=user^user=${updateData.assigned_to}`,
            sysparm_fields: "sys_id",
            sysparm_limit: 1,
          },
        })
        // If user has schedule, they're available
        // (Simplified check - full implementation would check current time against schedule)
      }
    } else if (auto_assign && resolvedGroupId) {
      // Auto-assign to group member with lowest workload
      const groupMembers = await client.get("/api/now/table/sys_user_grmember", {
        params: {
          sysparm_query: `group=${resolvedGroupId}^user.active=true`,
          sysparm_fields: "user",
          sysparm_limit: 100,
        },
      })

      if (groupMembers.data.result && groupMembers.data.result.length > 0) {
        const memberIds = groupMembers.data.result.map((m: any) => m.user.value)

        // Get workload for each member
        const workloads = await Promise.all(
          memberIds.map(async (userId: string) => {
            const workloadResponse = await client.get(`/api/now/table/${table}`, {
              params: {
                sysparm_query: `assigned_to=${userId}^active=true`,
                sysparm_fields: "sys_id",
                sysparm_limit: 1000,
              },
            })
            return {
              user_id: userId,
              count: workloadResponse.data.result?.length || 0,
            }
          }),
        )

        // Find member with lowest workload
        const leastBusy = workloads.reduce((min, curr) => (curr.count < min.count ? curr : min))

        updateData.assigned_to = leastBusy.user_id
      }
    }

    // Add work notes if provided
    if (work_notes) {
      updateData.work_notes = work_notes
    }

    // Update task
    const response = await client.put(`/api/now/table/${table}/${task.sys_id}`, updateData, {
      params: {
        sysparm_display_value: "all",
        sysparm_exclude_reference_link: "true",
      },
    })

    const updatedTask = response.data.result

    return createSuccessResult({
      assigned: true,
      number: updatedTask.number,
      sys_id: updatedTask.sys_id,
      previous_assigned_to: task.assigned_to,
      current_assigned_to: updatedTask.assigned_to,
      previous_assignment_group: task.assignment_group,
      current_assignment_group: updatedTask.assignment_group,
      auto_assigned: auto_assign && !assigned_to,
      task: {
        number: updatedTask.number,
        sys_id: updatedTask.sys_id,
        assigned_to: updatedTask.assigned_to,
        assignment_group: updatedTask.assignment_group,
      },
      url: `${context.instanceUrl}/${table}.do?sys_id=${updatedTask.sys_id}`,
    })
  } catch (error: any) {
    return createErrorResult(error instanceof SnowFlowError ? error : error.message)
  }
}

export const version = "1.0.0"
export const author = "Serac SDK Migration"
