/**
 * API Request Schemas
 * FE-TYPE-003: Create Zod schemas to validate API requests before sending
 *
 * Provides Zod schemas for all API request types to ensure type safety
 * and runtime validation of API requests before they are sent to the backend.
 */

import { z } from 'zod';
import { uuidSchema } from './apiSchemas';

/**
 * Email schema
 */
export const emailSchema = z.string().email('Invalid email format');

/**
 * Password schema (min 8 characters)
 */
export const passwordSchema = z
  .string()
  .min(8, 'Password must be at least 8 characters');

/**
 * Username schema
 */
export const usernameSchema = z
  .string()
  .min(3, 'Username must be at least 3 characters')
  .max(30, 'Username must be at most 30 characters')
  .regex(
    /^[a-zA-Z0-9_]+$/,
    'Username can only contain letters, numbers, and underscores',
  );

/**
 * Login request schema
 */
export const loginRequestSchema = z.object({
  email: emailSchema,
  password: z.string().min(1, 'Password is required'),
});

export type LoginRequest = z.infer<typeof loginRequestSchema>;

/**
 * Register request schema
 */
export const registerRequestSchema = z.object({
  username: usernameSchema,
  email: emailSchema,
  password: passwordSchema,
  first_name: z.string().max(100).optional(),
  last_name: z.string().max(100).optional(),
});

export type RegisterRequest = z.infer<typeof registerRequestSchema>;

/**
 * Two-Factor Authentication (2FA) Request Schemas
 * HIGH PRIORITY: Security feature - validation critical
 */

/**
 * Verify 2FA code request schema
 * POST /auth/2fa/verify
 */
export const verify2FARequestSchema = z.object({
  code: z
    .string()
    .min(6, 'TOTP code must be at least 6 characters')
    .max(6, 'TOTP code must be exactly 6 characters'),
  secret: z.string().min(1, 'Secret is required'),
});

export type Verify2FARequest = z.infer<typeof verify2FARequestSchema>;

/**
 * Disable 2FA request schema
 * POST /auth/2fa/disable
 */
export const disable2FARequestSchema = z.object({
  password: passwordSchema,
});

export type Disable2FARequest = z.infer<typeof disable2FARequestSchema>;

/**
 * Note: POST /auth/2fa/setup does not require a request body
 * It generates a secret and QR code for the authenticated user
 */

/**
 * Create user request schema
 */
export const createUserRequestSchema = z.object({
  username: usernameSchema,
  email: emailSchema,
  password: passwordSchema,
});

export type CreateUserRequest = z.infer<typeof createUserRequestSchema>;

/**
 * Update user request schema
 */
export const updateUserRequestSchema = z.object({
  username: usernameSchema.optional(),
  email: emailSchema.optional(),
  password: passwordSchema.optional(),
});

export type UpdateUserRequest = z.infer<typeof updateUserRequestSchema>;

/**
 * Update profile request schema
 */
export const updateProfileRequestSchema = z.object({
  first_name: z.string().max(100).optional(),
  last_name: z.string().max(100).optional(),
  username: usernameSchema.optional(),
  bio: z.string().max(500).optional(),
  location: z.string().max(100).optional(),
  birthdate: z
    .string()
    .regex(/^\d{4}-\d{2}-\d{2}$/, 'Invalid date format. Use YYYY-MM-DD')
    .optional(),
  gender: z.enum(['Male', 'Female', 'Other', 'Prefer not to say']).optional(),
});

export type UpdateProfileRequest = z.infer<typeof updateProfileRequestSchema>;

/**
 * Send message request schema
 */
export const sendMessageRequestSchema = z.object({
  conversation_id: uuidSchema,
  content: z.string().min(1, 'Message content is required'),
  message_type: z.enum(['text', 'image', 'audio', 'file']).optional(),
  attachment_url: z.string().url().optional(),
});

export type SendMessageRequest = z.infer<typeof sendMessageRequestSchema>;

/**
 * Update message request schema
 */
export const updateMessageRequestSchema = z.object({
  content: z.string().min(1, 'Message content is required').optional(),
});

export type UpdateMessageRequest = z.infer<typeof updateMessageRequestSchema>;

/**
 * Create conversation request schema
 */
export const createConversationRequestSchema = z.object({
  name: z.string().min(1, 'Conversation name is required'),
  type: z.enum(['direct', 'group']),
  participant_ids: z
    .array(uuidSchema)
    .min(1, 'At least one participant is required'),
});

export type CreateConversationRequest = z.infer<
  typeof createConversationRequestSchema
>;

/**
 * Update conversation request schema
 */
export const updateConversationRequestSchema = z.object({
  name: z.string().min(1, 'Conversation name is required').optional(),
});

export type UpdateConversationRequest = z.infer<
  typeof updateConversationRequestSchema
>;

/**
 * Batch Operations Request Schemas
 * MEDIUM PRIORITY: Core functionality
 */

/**
 * Batch delete tracks request schema
 * POST /tracks/batch/delete
 */
export const batchDeleteTracksRequestSchema = z.object({
  track_ids: z.array(uuidSchema).min(1, 'At least one track ID is required'),
});

export type BatchDeleteTracksRequest = z.infer<
  typeof batchDeleteTracksRequestSchema
>;

/**
 * Upload Chunking Request Schemas
 * MEDIUM PRIORITY: Core functionality for large file uploads
 */

/**
 * Initiate chunked upload request schema
 * POST /tracks/initiate
 */
export const initiateChunkedUploadRequestSchema = z.object({
  filename: z.string().min(1, 'Filename is required'),
  total_chunks: z.number().int().min(1, 'Total chunks must be at least 1'),
  total_size: z.number().int().min(1, 'Total size must be at least 1'),
});

export type InitiateChunkedUploadRequest = z.infer<
  typeof initiateChunkedUploadRequestSchema
>;

/**
 * Complete chunked upload request schema
 * POST /tracks/complete
 */
export const completeChunkedUploadRequestSchema = z.object({
  upload_id: z.string().min(1, 'Upload ID is required'),
});

export type CompleteChunkedUploadRequest = z.infer<
  typeof completeChunkedUploadRequestSchema
>;

/**
 * Upload chunk request schema
 * POST /tracks/chunk
 * Note: This endpoint uses formData (multipart/form-data), not JSON
 * The schema validates the form fields, but chunk file is validated separately
 */
export const uploadChunkRequestSchema = z.object({
  upload_id: z.string().min(1, 'Upload ID is required'),
  chunk_number: z.number().int().min(0, 'Chunk number must be non-negative'),
  total_chunks: z.number().int().min(1, 'Total chunks must be at least 1'),
  total_size: z.number().int().min(1, 'Total size must be at least 1'),
  filename: z.string().min(1, 'Filename is required'),
  // chunk file is sent as FormData file field, validated separately
});

export type UploadChunkRequest = z.infer<typeof uploadChunkRequestSchema>;

/**
 * Analytics Request Schemas
 * MEDIUM PRIORITY: Analytics tracking
 */

/**
 * Record analytics event request schema
 * POST /analytics/events
 */
export const recordEventRequestSchema = z.object({
  event_name: z
    .string()
    .min(1, 'Event name is required')
    .max(100, 'Event name must be at most 100 characters'),
  payload: z.record(z.any()).optional(), // Additional properties allowed
});

export type RecordEventRequest = z.infer<typeof recordEventRequestSchema>;

/**
 * Webhook Request Schemas
 * MEDIUM PRIORITY: Webhook management
 */

/**
 * Create webhook request schema
 * POST /webhooks
 * Note: Schema inferred from endpoint usage - webhook creation typically requires url, events, secret
 */
export const createWebhookRequestSchema = z.object({
  url: z.string().url('Invalid webhook URL'),
  events: z.array(z.string()).min(1, 'At least one event is required'),
  secret: z.string().min(1, 'Secret is required').optional(),
});

export type CreateWebhookRequest = z.infer<typeof createWebhookRequestSchema>;

/**
 * Frontend Logging Request Schemas
 * LOW PRIORITY: Development/debugging feature
 */

/**
 * Frontend log request schema
 * POST /api/v1/logs/frontend
 */
export const frontendLogRequestSchema = z.object({
  level: z.string().optional(),
  message: z.string().optional(),
  context: z.record(z.any()).optional(),
  timestamp: z.string().optional(),
  data: z.any().optional(),
});

export type FrontendLogRequest = z.infer<typeof frontendLogRequestSchema>;

/**
 * Email Verification Request Schemas
 * LOW PRIORITY: User account management
 */

/**
 * Resend verification email request schema
 * POST /auth/resend-verification
 */
export const resendVerificationRequestSchema = z.object({
  email: emailSchema,
});

export type ResendVerificationRequest = z.infer<
  typeof resendVerificationRequestSchema
>;

/**
 * Upload track request schema
 * Note: File objects cannot be validated with Zod, so we validate metadata only
 */
export const uploadTrackRequestSchema = z.object({
  title: z.string().min(1, 'Track title is required'),
  artist_id: uuidSchema,
  album_id: uuidSchema.optional(),
  genre: z.string().min(1, 'Genre is required'),
  // file and cover_art are File objects, validated separately
});

export type UploadTrackRequest = z.infer<typeof uploadTrackRequestSchema>;

/**
 * Update track request schema
 */
export const updateTrackRequestSchema = z.object({
  title: z.string().min(1, 'Track title is required').optional(),
  artist_id: uuidSchema.optional(),
  album_id: uuidSchema.optional(),
  genre: z.string().min(1, 'Genre is required').optional(),
});

export type UpdateTrackRequest = z.infer<typeof updateTrackRequestSchema>;

/**
 * Pagination params schema
 */
export const paginationParamsSchema = z.object({
  page: z.number().int().positive().optional(),
  limit: z.number().int().positive().max(100).optional(),
  cursor: z.string().optional(),
});

export type PaginationParams = z.infer<typeof paginationParamsSchema>;

/**
 * List users request schema
 */
export const listUsersRequestSchema = paginationParamsSchema.extend({
  query: z.string().optional(),
});

export type ListUsersRequest = z.infer<typeof listUsersRequestSchema>;

/**
 * List messages request schema
 */
export const listMessagesRequestSchema = paginationParamsSchema.extend({
  conversation_id: uuidSchema,
});

export type ListMessagesRequest = z.infer<typeof listMessagesRequestSchema>;

/**
 * List conversations request schema
 */
export const listConversationsRequestSchema = paginationParamsSchema.extend({
  query: z.string().optional(),
});

export type ListConversationsRequest = z.infer<
  typeof listConversationsRequestSchema
>;

/**
 * List tracks request schema
 */
export const listTracksRequestSchema = paginationParamsSchema.extend({
  artist: z.string().optional(),
  genre: z.string().optional(),
});

export type ListTracksRequest = z.infer<typeof listTracksRequestSchema>;

/**
 * Search tracks request schema
 */
export const searchTracksRequestSchema = paginationParamsSchema.extend({
  query: z.string().min(1, 'Search query is required'),
});

export type SearchTracksRequest = z.infer<typeof searchTracksRequestSchema>;

/**
 * Upload file request schema
 * Note: File object cannot be validated with Zod
 */
export const uploadFileRequestSchema = z.object({
  type: z.enum(['image', 'audio', 'document']),
  // file is a File object, validated separately
});

export type UploadFileRequest = z.infer<typeof uploadFileRequestSchema>;

/**
 * Validate API request data
 *
 * @param schema - Zod schema to validate against
 * @param data - Data to validate
 * @returns Validated data
 * @throws ZodError if validation fails
 */
export function validateApiRequest<T>(
  schema: z.ZodSchema<T>,
  data: unknown,
): T {
  return schema.parse(data);
}

/**
 * Safe validate API request (returns result instead of throwing)
 *
 * @param schema - Zod schema to validate against
 * @param data - Data to validate
 * @returns Validation result
 */
export function safeValidateApiRequest<T>(
  schema: z.ZodSchema<T>,
  data: unknown,
): {
  success: boolean;
  data?: T;
  error?: z.ZodError;
} {
  try {
    const validated = validateApiRequest(schema, data);
    return { success: true, data: validated };
  } catch (error) {
    if (error instanceof z.ZodError) {
      return { success: false, error };
    }
    throw error;
  }
}

/**
 * Validate request with custom error handling
 *
 * @param schema - Zod schema to validate against
 * @param data - Data to validate
 * @param onError - Optional error handler
 * @returns Validated data or throws
 */
export function validateApiRequestWithError<T>(
  schema: z.ZodSchema<T>,
  data: unknown,
  onError?: (error: z.ZodError) => void,
): T {
  try {
    return schema.parse(data);
  } catch (error) {
    if (error instanceof z.ZodError && onError) {
      onError(error);
    }
    throw error;
  }
}
