/**
 * Schema Validation Module
 * 
 * Input/output validation for the DailyNotification plugin bridge
 * Ensures type safety and data integrity at the JavaScript boundary
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 */

import { 
  type ValidationResult, 
  ErrorCode,
  type PriorityType,
  type PermissionType 
} from './bridge'

export class SchemaValidator {
  
  /**
   * Validate schedule request input
   */
  validateScheduleRequest(request: unknown): ValidationResult {
    const errors: string[] = []

    // Type guard: ensure request is an object
    if (!request || typeof request !== 'object') {
      return {
        isValid: false,
        errors: ['Request must be an object'],
        message: 'Request must be an object'
      }
    }

    const req = request as Record<string, unknown>

    // Validate time format (HH:mm)
    if (!this.isValidTimeFormat(req.time as string)) {
      errors.push('Time must be in HH:mm format (24-hour)')
    }

    // Validate title length (enforce exactly: title ≤ 100 chars)
    if (req.title && typeof req.title === 'string' && req.title.length > 100) {
      errors.push('Title must be 100 characters or less')
    }

    // Validate body length (enforce exactly: body ≤ 500 chars)
    if (req.body && typeof req.body === 'string' && req.body.length > 500) {
      errors.push('Body must be 500 characters or less')
    }

    // Validate boolean fields
    if (typeof req.sound !== 'boolean') {
      errors.push('Sound must be a boolean')
    }

    // Validate priority
    if (!this.isValidPriority(req.priority)) {
      errors.push('Priority must be low, default, or high')
    }

    // Reject unknown fields
    const allowedFields = ['time', 'title', 'body', 'sound', 'priority']
    const unknownFields = Object.keys(req).filter(key => !allowedFields.includes(key))
    if (unknownFields.length > 0) {
      errors.push(`Unknown fields: ${unknownFields.join(', ')}`)
    }

    return {
      isValid: errors.length === 0,
      errors,
      message: errors.join('; ') // Single joined message for UI display
    }
  }

  /**
   * Validate permission status response
   */
  validatePermissionStatus(status: unknown): ValidationResult {
    const errors: string[] = []
    const statusObj = status as Record<string, unknown>

    if (!this.isValidPermissionType(statusObj.notifications)) {
      errors.push('Notifications permission must be granted or denied')
    }

    if (typeof statusObj.notificationsEnabled !== 'boolean') {
      errors.push('NotificationsEnabled must be a boolean')
    }

    return {
      isValid: errors.length === 0,
      errors,
      message: errors.join('; ')
    }
  }

  /**
   * Validate notification status response
   */
  validateNotificationStatus(status: unknown): ValidationResult {
    const errors: string[] = []
    const statusObj = status as Record<string, unknown>

    if (typeof statusObj.isEnabled !== 'boolean') {
      errors.push('IsEnabled must be a boolean')
    }

    if (typeof statusObj.isScheduled !== 'boolean') {
      errors.push('IsScheduled must be a boolean')
    }

    if (typeof statusObj.pending !== 'boolean') {
      errors.push('Pending must be a boolean')
    }

    return {
      isValid: errors.length === 0,
      errors,
      message: errors.join('; ')
    }
  }

  /**
   * Validate exact alarm status response
   */
  validateExactAlarmStatus(status: unknown): ValidationResult {
    const errors: string[] = []
    const statusObj = status as Record<string, unknown>

    if (typeof statusObj.enabled !== 'boolean') {
      errors.push('Enabled must be a boolean')
    }

    if (typeof statusObj.supported !== 'boolean') {
      errors.push('Supported must be a boolean')
    }

    return {
      isValid: errors.length === 0,
      errors,
      message: errors.join('; ')
    }
  }

  /**
   * Check if time format is valid (HH:mm)
   */
  private isValidTimeFormat(time: string): boolean {
    if (typeof time !== 'string') return false
    
    const timeRegex = /^([01]?[0-9]|2[0-3]):[0-5][0-9]$/
    return timeRegex.test(time)
  }

  /**
   * Check if priority is valid
   */
  private isValidPriority(priority: unknown): priority is PriorityType {
    return typeof priority === 'string' && ['low', 'default', 'high'].includes(priority)
  }

  /**
   * Check if permission type is valid
   */
  private isValidPermissionType(permission: unknown): permission is PermissionType {
    return typeof permission === 'string' && ['granted', 'denied'].includes(permission)
  }

  /**
   * Create canonical error response
   */
  createErrorResponse(code: ErrorCode, message: string, hint?: string): {
    success: false
    error: {
      code: ErrorCode
      message: string
      hint?: string
    }
  } {
    return {
      success: false,
      error: {
        code,
        message,
        hint
      }
    }
  }

  /**
   * Create success response
   */
  createSuccessResponse(data?: Record<string, unknown>): {
    success: true
    [key: string]: unknown
  } {
    return {
      success: true,
      ...data
    }
  }
}

// Singleton instance
export const schemaValidator = new SchemaValidator()

// Utility functions
export function validateScheduleRequest(request: unknown): ValidationResult {
  return schemaValidator.validateScheduleRequest(request)
}

export function validatePermissionStatus(status: unknown): ValidationResult {
  return schemaValidator.validatePermissionStatus(status)
}

export function validateNotificationStatus(status: unknown): ValidationResult {
  return schemaValidator.validateNotificationStatus(status)
}

export function validateExactAlarmStatus(status: unknown): ValidationResult {
  return schemaValidator.validateExactAlarmStatus(status)
}
