/**
 * Validation utility functions
 */

import type {
  RecommendRequest,
  ValidationError,
  Server,
  VPSBenchmark,
  TechSpec,
  BenchmarkData,
  AIRecommendationResponse
} from '../types';
import { i18n, LIMITS } from '../config';

/**
 * Type guard to validate Server object structure
 */
export function isValidServer(obj: unknown): obj is Server {
  if (!obj || typeof obj !== 'object') return false;
  const s = obj as Record<string, unknown>;
  return (
    typeof s.id === 'number' &&
    typeof s.provider_name === 'string' &&
    typeof s.instance_id === 'string' &&
    typeof s.vcpu === 'number' &&
    typeof s.memory_mb === 'number' &&
    typeof s.monthly_price === 'number'
  );
}

/**
 * Type guard to validate VPSBenchmark object structure
 */
export function isValidVPSBenchmark(obj: unknown): obj is VPSBenchmark {
  if (!obj || typeof obj !== 'object') return false;
  const v = obj as Record<string, unknown>;
  return (
    typeof v.id === 'number' &&
    typeof v.provider_name === 'string' &&
    typeof v.vcpu === 'number' &&
    typeof v.geekbench_single === 'number'
  );
}

/**
 * Type guard to validate TechSpec object structure
 */
export function isValidTechSpec(obj: unknown): obj is TechSpec {
  if (!obj || typeof obj !== 'object') return false;
  const t = obj as Record<string, unknown>;
  return (
    typeof t.id === 'number' &&
    typeof t.name === 'string' &&
    typeof t.vcpu_per_users === 'number' &&
    typeof t.min_memory_mb === 'number'
  );
}

/**
 * Type guard to validate BenchmarkData object structure
 */
export function isValidBenchmarkData(obj: unknown): obj is BenchmarkData {
  if (!obj || typeof obj !== 'object') return false;
  const b = obj as Record<string, unknown>;
  return (
    typeof b.id === 'number' &&
    typeof b.processor_name === 'string' &&
    typeof b.benchmark_name === 'string' &&
    typeof b.score === 'number'
  );
}

/**
 * Type guard to validate AI recommendation structure
 */
export function isValidAIRecommendation(obj: unknown): obj is AIRecommendationResponse['recommendations'][0] {
  if (!obj || typeof obj !== 'object') return false;
  const r = obj as Record<string, unknown>;
  return (
    (typeof r.server_id === 'number' || typeof r.server_id === 'string') &&
    typeof r.score === 'number' &&
    r.analysis !== null &&
    typeof r.analysis === 'object' &&
    r.estimated_capacity !== null &&
    typeof r.estimated_capacity === 'object'
  );
}

/**
 * Validate recommendation request
 */
export function validateRecommendRequest(body: unknown, lang: string = 'en'): ValidationError | null {
  // Ensure lang is valid
  const validLang = ['en', 'zh', 'ja', 'ko'].includes(lang) ? lang : 'en';
  const messages = i18n[validLang];

  if (!body || typeof body !== 'object') {
    return {
      error: 'Request body must be a JSON object',
      missing_fields: ['tech_stack', 'expected_users', 'use_case'],
      schema: messages.schema,
      example: messages.example
    };
  }

  // Type guard: assert body is an object with unknown properties
  const req = body as Record<string, unknown>;

  const missingFields: string[] = [];
  const invalidFields: { field: string; reason: string }[] = [];

  // Check required fields
  if (!req.tech_stack) {
    missingFields.push('tech_stack');
  } else if (!Array.isArray(req.tech_stack) || req.tech_stack.length === 0) {
    invalidFields.push({ field: 'tech_stack', reason: 'must be a non-empty array of strings' });
  } else if (req.tech_stack.length > LIMITS.MAX_TECH_STACK) {
    invalidFields.push({ field: 'tech_stack', reason: `must not exceed ${LIMITS.MAX_TECH_STACK} items` });
  } else if (!req.tech_stack.every((item: unknown) =>
    typeof item === 'string' && item.length <= 50
  )) {
    invalidFields.push({ field: 'tech_stack', reason: messages.techStackItemLength || 'all items must be strings with max 50 characters' });
  }

  if (req.expected_users === undefined) {
    missingFields.push('expected_users');
  } else if (typeof req.expected_users !== 'number' || req.expected_users < 1) {
    invalidFields.push({ field: 'expected_users', reason: 'must be a positive number' });
  } else if (req.expected_users > 10000000) {
    invalidFields.push({ field: 'expected_users', reason: 'must not exceed 10,000,000' });
  }

  if (!req.use_case) {
    missingFields.push('use_case');
  } else if (typeof req.use_case !== 'string' || req.use_case.trim().length === 0) {
    invalidFields.push({ field: 'use_case', reason: 'must be a non-empty string' });
  } else if (req.use_case.length > LIMITS.MAX_USE_CASE_LENGTH) {
    invalidFields.push({ field: 'use_case', reason: `must not exceed ${LIMITS.MAX_USE_CASE_LENGTH} characters` });
  }

  // Check optional fields if provided
  if (req.traffic_pattern !== undefined && !['steady', 'spiky', 'growing'].includes(req.traffic_pattern as string)) {
    invalidFields.push({ field: 'traffic_pattern', reason: "must be one of: 'steady', 'spiky', 'growing'" });
  }

  if (req.budget_limit !== undefined && (typeof req.budget_limit !== 'number' || req.budget_limit < 0)) {
    invalidFields.push({ field: 'budget_limit', reason: 'must be a non-negative number' });
  }

  // Validate lang field if provided
  if (req.lang !== undefined && !['en', 'zh', 'ja', 'ko'].includes(req.lang as string)) {
    invalidFields.push({ field: 'lang', reason: "must be one of: 'en', 'zh', 'ja', 'ko'" });
  }

  // Validate region_preference if provided
  if (req.region_preference !== undefined) {
    if (!Array.isArray(req.region_preference)) {
      invalidFields.push({ field: 'region_preference', reason: 'must be an array of strings' });
    } else if (req.region_preference.length > LIMITS.MAX_REGION_PREFERENCE) {
      invalidFields.push({ field: 'region_preference', reason: `must not exceed ${LIMITS.MAX_REGION_PREFERENCE} items` });
    } else if (!req.region_preference.every((r: unknown) => typeof r === 'string' && r.length > 0 && r.length <= 50)) {
      invalidFields.push({ field: 'region_preference', reason: 'all items must be non-empty strings with max 50 characters' });
    }
  }

  // Return error if any issues found
  if (missingFields.length > 0 || invalidFields.length > 0) {
    return {
      error: missingFields.length > 0 ? messages.missingFields : messages.invalidFields,
      ...(missingFields.length > 0 && { missing_fields: missingFields }),
      ...(invalidFields.length > 0 && { invalid_fields: invalidFields }),
      schema: messages.schema,
      example: messages.example
    };
  }

  return null;
}
