/**
 * Users Domain - Zod Validation Schemas
 *
 * Validation schemas for user management endpoints.
 * Includes request bodies, query params, and path params.
 *
 * Security:
 * - All schemas use .strict() to prevent mass assignment attacks
 * - UUID validation prevents invalid references
 * - Email validation prevents email injection attacks
 * - emailVerified field excluded from create/update (admin-only)
 * - String length limits prevent DoS
 */

import { z } from 'zod'
import { EmailSchema, createStringSchema } from '../../../platform/utils/validation'
import { ThemePresetEnum } from '../theme-presets'

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

/**
 * Validate user ID in URL path
 * Used by: GET/PUT/DELETE /users/:id
 */
export const UserIdParamSchema = z
  .object({
    id: z.string().min(1) // WorkOS user IDs can be UUID or 'user_' prefixed strings
  })
  .strict()

/**
 * Validate external ID in URL path
 * Used by: GET /users/external/:externalId
 */
export const ExternalIdParamSchema = z
  .object({
    externalId: z.string().min(1)
  })
  .strict()

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

/**
 * Update user profile
 * PUT /users/:id
 *
 * Security:
 * - All fields optional (partial update)
 * - Email format validated
 * - emailVerified NOT accepted (managed by WorkOS only)
 * - Strict mode prevents unknown field injection
 */
export const UpdateUserSchema = z
  .object({
    email: EmailSchema.optional(),
    firstName: createStringSchema(1, 100, 'First name').optional(),
    lastName: createStringSchema(1, 100, 'Last name').optional()
  })
  .strict()

// ============================================================================
// Self-Service Profile
// ============================================================================

/**
 * Self-service profile update (subset of admin UpdateUserSchema)
 * PATCH /users/me
 *
 * Security:
 * - All fields optional (partial update)
 * - Server identifies user from JWT (no user ID in body)
 * - Config restricted to theme and onboarding only
 * - Strict mode prevents unknown field injection
 */
export const UpdateMyProfileSchema = z
  .object({
    firstName: createStringSchema(1, 100, 'First name').optional(),
    lastName: createStringSchema(1, 100, 'Last name').optional(),
    profilePictureUrl: z
      .string()
      .url()
      .refine((url) => url.startsWith('https://'), { message: 'Only HTTPS URLs are allowed' })
      .optional(),
    lastVisitedOrg: z.string().uuid().optional(),
    config: z
      .object({
        theme: z
          .object({
            // `.catch('default')` makes the write path tolerant of stale/unknown preset strings.
            // Any value that fails enum validation silently coerces to 'default' instead of 400ing.
            // This protects against preset renames (e.g. cyber-punk → cyber-chrome) and drift between
            // the enum and legacy DB values. Paired with a read-path sync-back in main.tsx that
            // persists the corrected value back to DB on next profile load.
            // ThemePresetEnum is derived from THEME_PRESETS — the single source of truth in
            // packages/core/src/auth/multi-tenancy/theme-presets.ts.
            preset: ThemePresetEnum.catch('default').optional(),
            colorScheme: z.enum(['light', 'dark', 'auto']).catch('auto').optional()
          })
          .strict()
          .optional(),
        onboarding: z
          .object({
            completed: z.boolean().optional(),
            completedAt: z.string().datetime().nullable().optional(),
            role: z.string().max(100).nullable().optional(),
            primaryUseCase: z.array(z.string().max(100)).max(10).nullable().optional(),
            experienceLevel: z.string().max(100).nullable().optional(),
            guides: z
              .object({
                completedIds: z.array(z.string().max(100)).max(20).optional(),
                dismissed: z.boolean().optional(),
                completedAt: z.string().datetime().nullable().optional()
              })
              .strict()
              .optional()
          })
          .strict()
          .optional()
      })
      .strict()
      .optional()
  })
  .strict()

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

/**
 * List users with filters
 * GET /users
 *
 * Filters:
 * - email: Filter by email
 * - organizationId: Filter by organization
 * - limit: Max results (pagination handled by WorkOS)
 *
 * Security:
 * - Email validated (prevents injection)
 * - organizationId validated (UUID format)
 */
export const ListUsersQuerySchema = z
  .object({
    email: EmailSchema.optional(),
    organizationId: z.string().optional(), // WorkOS org IDs can be UUID or 'org_' prefixed
    limit: z.coerce.number().int().min(1).max(100).optional(),
    before: z.string().optional(), // WorkOS pagination cursor
    after: z.string().optional() // WorkOS pagination cursor
  })
  .strict()

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

// Export inferred types for use in route handlers
export type UpdateUserInput = z.infer<typeof UpdateUserSchema>
export type UpdateMyProfileInput = z.infer<typeof UpdateMyProfileSchema>
export type ListUsersQuery = z.infer<typeof ListUsersQuerySchema>
export type UserIdParam = z.infer<typeof UserIdParamSchema>
export type ExternalIdParam = z.infer<typeof ExternalIdParamSchema>
