/**
 * Sessions Domain - Zod Validation Schemas
 *
 * Validation schemas for session management endpoints.
 * Includes request bodies, query params, path params, and WebSocket messages.
 *
 * Security:
 * - All schemas use .strict() to prevent mass assignment attacks
 * - UUID validation prevents invalid references
 * - String length limits prevent DoS (+ token counter at 10k tokens)
 * - organizationId never accepted in request body (taken from JWT)
 */

import { z } from 'zod'
import { UuidSchema } from '../../platform/utils/validation'

// Re-export UuidSchema for convenience
export { UuidSchema }

// ============================================================================
// Path Parameters
// ============================================================================

/**
 * Validate sessionId in URL path
 * Used by: GET/DELETE /sessions/:sessionId, GET /sessions/:sessionId/messages
 */
export const SessionIdParamSchema = z
  .object({
    sessionId: UuidSchema
  })
  .strict()

/**
 * Validate sessionId + executionId in URL path
 * Used by: GET /sessions/:sessionId/executions/:executionId
 */
export const ExecutionIdParamsSchema = z
  .object({
    sessionId: UuidSchema,
    executionId: UuidSchema
  })
  .strict()

// ============================================================================
// Request Bodies
// ============================================================================

/**
 * Create new session
 * POST /sessions
 *
 * Security:
 * - resourceId is string identifier (e.g., 'basic-agent', 'linear-test-workflow')
 * - userId optional (for user-specific sessions)
 * - metadata optional (arbitrary JSON for agent use)
 * - organizationId NOT accepted (taken from JWT)
 */
export const CreateSessionSchema = z
  .object({
    resourceId: z.string().min(1).max(100),
    userId: UuidSchema.optional(),
    metadata: z.any().optional()
  })
  .strict()

/**
 * Execute session turn
 * POST /sessions/:sessionId/turns
 *
 * Supports string, object, and any JSON-serializable input formats
 *
 * Security:
 * - Input length max 100k chars (supports long-form AI interactions)
 * - Prompt injection blocked by input-sanitizer before execution
 * - Strict mode prevents metadata injection
 */
export const ExecuteTurnSchema = z
  .object({
    input: z.unknown().refine(
      (val) => {
        let text: string
        if (typeof val === 'string') {
          text = val
        } else if (val && typeof val === 'object' && 'message' in val) {
          text = String((val as Record<string, unknown>).message)
        } else {
          text = JSON.stringify(val)
        }
        return text.length > 0 && text.length <= 100_000
      },
      { message: 'Input must be between 1 and 100,000 characters' }
    ),
    metadata: z.any().optional()
  })
  .strict()

// ============================================================================
// Query Parameters
// ============================================================================

/**
 * List sessions with filters
 * GET /sessions
 *
 * Filters:
 * - userId: Filter by user (UUID)
 * - resourceId: Filter by agent/resource (string identifier like 'executive-agent')
 * - limit: Max results (1-100, default 20)
 *
 * Security:
 * - userId validated as UUID (prevents SQL injection)
 * - resourceId validated as string (resource identifiers)
 * - Limit bounded (prevents DoS via large result sets)
 */
export const ListSessionsQuerySchema = z
  .object({
    userId: UuidSchema.optional(),
    resourceId: z.string().optional(),
    limit: z.coerce.number().int().min(1).max(100).default(20)
  })
  .strict()

/**
 * Get session messages with cursor pagination
 * GET /sessions/:sessionId/messages
 *
 * Cursor:
 * - cursor is the last seen message_index
 * - next page returns rows where message_index > cursor
 *
 * Security:
 * - Limit bounded to prevent unbounded transcript reads
 * - Cursor coerced and validated as a non-negative integer
 */
export const SessionMessagesQuerySchema = z
  .object({
    limit: z.coerce.number().int().min(1).max(100).default(100),
    cursor: z.coerce.number().int().min(0).optional()
  })
  .strict()

// ============================================================================
// WebSocket Messages
// ============================================================================

/**
 * WebSocket client message: Execute turn
 *
 * Client sends: { type: "session:turn", input: "..." }
 *
 * Security:
 * - Same input validation as HTTP endpoint (100k char limit)
 * - Token limit also validated separately (10k tokens for CHAT_MESSAGE)
 * - Prompt injection blocked by input-sanitizer
 */
export const WebSocketSessionTurnSchema = z
  .object({
    type: z.literal('session:turn'),
    input: z.unknown().refine(
      (val) => {
        let text: string
        if (typeof val === 'string') {
          text = val
        } else if (val && typeof val === 'object' && 'message' in val) {
          text = String((val as Record<string, unknown>).message)
        } else {
          text = JSON.stringify(val) || ''
        }
        return text && text.length > 0 && text.length <= 100_000
      },
      { message: 'Input must be between 1 and 100,000 characters' }
    )
  })
  .strict()

// ============================================================================
// TypeScript Type Exports
// ============================================================================

// Export inferred types for use in route handlers
export type CreateSessionInput = z.infer<typeof CreateSessionSchema>
export type ExecuteTurnInput = z.infer<typeof ExecuteTurnSchema>
export type ListSessionsQuery = z.infer<typeof ListSessionsQuerySchema>
export type SessionMessagesQuery = z.infer<typeof SessionMessagesQuerySchema>
export type WebSocketSessionTurnMessage = z.infer<typeof WebSocketSessionTurnSchema>
