import { z } from 'zod'
import { ResourceTypeSchema, OriginResourceTypeSchema } from '../../platform/utils/validation'
import { TaskScheduleConfigSchema } from './schemas'

/**
 * API validation schemas for task scheduler endpoints.
 * Separate from domain schemas (schemas.ts) to enforce validation at API boundary.
 *
 * Note: Domain schemas in schemas.ts define business logic validation.
 * API schemas add transport-layer concerns (query params, path params, response validation).
 *
 * Schedule config schemas (TaskScheduleConfigSchema, RecurringScheduleConfigSchema, etc.)
 * are defined in schemas.ts and exported from there. This file only defines API-specific
 * request/response schemas.
 */

// ============================================================================
// REQUEST SCHEMAS (NEW UNIFIED SYSTEM)
// ============================================================================

/**
 * POST /api/task-scheduler/schedules - Create a new schedule
 *
 * Security:
 * - organizationId extracted from JWT auth context (not in request body)
 * - Strict mode prevents unknown fields (prevents mass assignment)
 * - UUID validation on optional origin fields
 * - Name/description length limited to prevent abuse
 */
export const CreateScheduleRequestSchema = z.object({
  name: z.string().min(1, 'Name is required').max(255),
  description: z.string().max(1000).optional(),

  target: z.object({
    resourceType: ResourceTypeSchema,
    resourceId: z.string().min(1, 'Resource ID is required').max(255)
  }),

  scheduleConfig: TaskScheduleConfigSchema,

  maxRetries: z.number().int().min(0).max(10).optional(),
  idempotencyKey: z.string().max(255).optional(),

  // Origin tracking (optional)
  originExecutionId: z.string().uuid().optional(),
  originResourceType: OriginResourceTypeSchema.optional(),
  originResourceId: z.string().max(255).optional()
})

/**
 * GET /api/task-scheduler/schedules - List schedules with filters
 *
 * Security:
 * - Enum validation restricts to valid status/resource type values
 * - z.coerce handles string query params from URL
 * - Limit capped at 100 to prevent memory exhaustion
 */
export const ListSchedulesQuerySchema = z.object({
  status: z.enum(['active', 'paused', 'completed', 'cancelled']).optional(),
  targetResourceType: ResourceTypeSchema.optional(),
  targetResourceId: z.string().optional(),
  limit: z.coerce.number().int().min(1).max(100).optional().default(50),
  offset: z.coerce.number().int().min(0).optional().default(0)
})

/**
 * GET /api/task-scheduler/schedules/:id - Get single schedule
 *
 * Security:
 * - UUID validation prevents SQL injection via path params
 */
export const GetScheduleParamsSchema = z.object({
  id: z.string().uuid('Invalid schedule ID')
})

/**
 * PATCH /api/task-scheduler/schedules/:id/anchor - Update anchor for relative schedules
 *
 * Security:
 * - Datetime validation ensures valid ISO 8601 format
 * - Only applicable to relative schedules (checked at service layer)
 */
export const UpdateAnchorRequestSchema = z.object({
  anchorAt: z.string().datetime({ message: 'Invalid anchor datetime format' })
})

/**
 * PATCH /api/task-scheduler/schedules/:id - Update schedule fields
 *
 * Security:
 * - Strict mode prevents unknown fields (no mass assignment)
 * - At least one field must be provided
 * - Schedule config re-validated with discriminated union
 * - Only active/paused schedules can be updated (checked at service layer)
 */
export const UpdateScheduleRequestSchema = z
  .object({
    name: z.string().min(1, 'Name cannot be empty').max(255).optional(),
    description: z.string().max(1000).nullable().optional(),
    scheduleConfig: TaskScheduleConfigSchema.optional(),
    maxRetries: z.number().int().min(0).max(10).optional()
  })
  .strict()
  .refine(
    (data) =>
      data.name !== undefined ||
      data.description !== undefined ||
      data.scheduleConfig !== undefined ||
      data.maxRetries !== undefined,
    { message: 'At least one field (name, description, scheduleConfig, maxRetries) must be provided' }
  )

/**
 * POST /api/task-scheduler/process-batch - Internal webhook from pg_cron
 * Note: This endpoint is called by the database, not by users
 *
 * Security:
 * - No authentication (internal database trigger only, not exposed externally)
 * - Validates database row structure (snake_case columns)
 * - Batch size limited to 1-100 schedules
 * - UUID validation on ID fields
 */
export const ProcessSchedulesBatchRequestSchema = z.object({
  schedules: z
    .array(
      z.object({
        // Required identifiers
        id: z.string().uuid(),
        organization_id: z.string().uuid(),
        name: z.string(),

        // Target
        target_resource_type: z.string(),
        target_resource_id: z.string(),

        // Schedule definition
        schedule_config: z.record(z.string(), z.unknown()), // JSONB from database
        current_step: z.number().int(),
        status: z.string(),

        // Scheduling state
        next_run_at: z.string().nullable(),
        last_run_at: z.string().nullable(),
        last_execution_id: z.string().uuid().nullable(),

        // Config
        max_retries: z.number().int(),
        retry_count: z.number().int(),
        idempotency_key: z.string().nullable(),
        description: z.string().nullable(),

        // Origin tracking
        origin_execution_id: z.string().uuid().nullable(),
        origin_resource_type: z.string().nullable(),
        origin_resource_id: z.string().nullable(),

        // Timestamps (PostgreSQL format with microseconds)
        created_at: z.string(),
        updated_at: z.string()
      })
    )
    .min(1)
    .max(100)
})

/**
 * GET /api/task-scheduler/schedules/:id/executions - Get execution history
 *
 * Security:
 * - UUID validation on schedule ID path param
 */
export const GetExecutionHistoryParamsSchema = z.object({
  id: z.string().uuid('Invalid schedule ID')
})

/**
 * Query parameters for execution history pagination
 */
export const GetExecutionHistoryQuerySchema = z.object({
  limit: z.coerce.number().int().min(1).max(100).optional().default(20),
  offset: z.coerce.number().int().min(0).optional().default(0)
})

// ============================================================================
// RESPONSE SCHEMAS (NEW UNIFIED SYSTEM)
// ============================================================================

/**
 * Single schedule response.
 * Returned by GET /schedules/:id and POST /schedules
 */
export const ScheduleResponseSchema = z.object({
  id: z.string().uuid(),
  organizationId: z.string().uuid(),
  name: z.string(),
  description: z.string().nullable(),

  target: z.object({
    resourceType: ResourceTypeSchema,
    resourceId: z.string()
  }),

  scheduleConfig: TaskScheduleConfigSchema,

  nextRunAt: z.string().datetime().nullable(),
  currentStep: z.number().int(),
  status: z.enum(['active', 'paused', 'completed', 'cancelled']),

  lastRunAt: z.string().datetime().nullable(),
  lastExecutionId: z.string().uuid().nullable(),

  maxRetries: z.number().int(),
  idempotencyKey: z.string().nullable(),

  createdAt: z.string().datetime(),
  updatedAt: z.string().datetime()
})

/**
 * List schedules response.
 * Returned by GET /schedules with pagination metadata.
 */
export const ListSchedulesResponseSchema = z.object({
  schedules: z.array(ScheduleResponseSchema),
  total: z.number().int(),
  limit: z.number().int(),
  offset: z.number().int()
})

/**
 * Execution history item.
 * Represents a single execution triggered by a schedule.
 */
export const ExecutionHistoryItemSchema = z.object({
  id: z.string().uuid(),
  createdAt: z.string().datetime(),
  status: z.enum(['running', 'completed', 'failed', 'cancelled']),
  step: z.number().int().nullable(),
  itemLabel: z.string().nullable(),
  duration: z.number().nullable(), // milliseconds
  error: z.string().nullable()
})

/**
 * Execution history response.
 * Returned by GET /schedules/:id/executions with pagination.
 */
export const ExecutionHistoryResponseSchema = z.object({
  executions: z.array(ExecutionHistoryItemSchema),
  total: z.number().int(),
  limit: z.number().int(),
  offset: z.number().int()
})

/**
 * Process batch response (internal).
 * Returned by POST /process-batch for monitoring/debugging.
 */
export const ProcessBatchResponseSchema = z.object({
  processed: z.number().int(),
  succeeded: z.number().int(),
  failed: z.number().int(),
  errors: z
    .array(
      z.object({
        scheduleId: z.string().uuid(),
        error: z.string()
      })
    )
    .optional()
})

// ============================================================================
// TYPE EXPORTS (NEW UNIFIED SYSTEM)
// ============================================================================

// Note: Schedule config types (RecurringScheduleConfig, RelativeScheduleConfig,
// AbsoluteScheduleConfig, TaskScheduleConfig, RelativeScheduleItem, AbsoluteScheduleItem)
// are defined in types.ts. Import them from there or from the package index.

// Request types
export type CreateScheduleRequest = z.infer<typeof CreateScheduleRequestSchema>
export type ListSchedulesQuery = z.infer<typeof ListSchedulesQuerySchema>
export type GetScheduleParams = z.infer<typeof GetScheduleParamsSchema>
export type UpdateAnchorRequest = z.infer<typeof UpdateAnchorRequestSchema>
export type UpdateScheduleRequest = z.infer<typeof UpdateScheduleRequestSchema>
export type ProcessSchedulesBatchRequest = z.infer<typeof ProcessSchedulesBatchRequestSchema>
export type GetExecutionHistoryParams = z.infer<typeof GetExecutionHistoryParamsSchema>
export type GetExecutionHistoryQuery = z.infer<typeof GetExecutionHistoryQuerySchema>

// Response types
export type ScheduleResponse = z.infer<typeof ScheduleResponseSchema>
export type ListSchedulesResponse = z.infer<typeof ListSchedulesResponseSchema>
export type ExecutionHistoryItem = z.infer<typeof ExecutionHistoryItemSchema>
export type ExecutionHistoryResponse = z.infer<typeof ExecutionHistoryResponseSchema>
export type ProcessBatchResponse = z.infer<typeof ProcessBatchResponseSchema>
