/**
 * Survey Client — Browser/React Native-safe survey client
 * @module @bytelyst/survey-client
 */

// =============================================================================
// Types
// =============================================================================

export type QuestionType =
  | 'single_choice'
  | 'multiple_choice'
  | 'rating'
  | 'nps'
  | 'text_short'
  | 'text_long'
  | 'dropdown'
  | 'scale'
  | 'ranking';

export interface QuestionOption {
  id: string;
  text: string;
  emoji?: string;
}

export interface Question {
  id: string;
  type: QuestionType;
  text: string;
  description?: string;
  required: boolean;
  options?: QuestionOption[];
  minLength?: number;
  maxLength?: number;
  minValue?: number;
  maxValue?: number;
}

export interface Survey {
  id: string;
  productId: string;
  title: string;
  description?: string;
  questions: Question[];
  status: 'draft' | 'active' | 'paused' | 'closed';
  startsAt?: string;
  endsAt?: string;
  displayTrigger:
    | { type: 'immediate' }
    | { type: 'delay_seconds'; seconds: number }
    | { type: 'event'; eventName: string }
    | { type: 'page_view'; pagePattern: string };
  incentive?: { type: 'pro_days' | 'credits'; amount: number };
  createdAt: string;
  updatedAt: string;
  createdBy: string;
}

export type QuestionAnswer =
  | { type: 'single_choice'; optionId: string }
  | { type: 'multiple_choice'; optionIds: string[] }
  | { type: 'rating'; value: number }
  | { type: 'nps'; value: number }
  | { type: 'text'; value: string }
  | { type: 'ranking'; rankedOptionIds: string[] };

export interface SurveyResponse {
  id: string;
  surveyId: string;
  userId: string;
  answers: Record<string, QuestionAnswer>;
  currentQuestionIndex: number;
  startedAt: string;
  completedAt?: string;
  isComplete: boolean;
  incentiveClaimed: boolean;
  incentiveClaimedAt?: string;
  createdAt: string;
  updatedAt: string;
}

export interface SurveyClientConfig {
  /** Platform service base URL */
  baseUrl: string;
  /** Product ID */
  productId: string;
  /** Auth token provider */
  getAuthToken: (() => string) | (() => Promise<string>);
  /** Platform identifier */
  platform: 'web' | 'ios' | 'android' | 'macos' | 'windows';
  /** App version */
  appVersion: string;
  /** OS version */
  osVersion: string;
  /** Optional country code */
  countryCode?: string;
  /** Optional region code */
  regionCode?: string;
  /** User segments (default: ['free']) */
  userSegments?: string[];
  /** Device ID for tracking */
  deviceId?: string;
}

// =============================================================================
// Client Factory
// =============================================================================

export interface ActiveSurvey {
  id: string;
  title: string;
  description?: string;
  questions: Question[];
  incentive?: { type: 'pro_days' | 'credits'; amount: number };
  displayTrigger: Survey['displayTrigger'];
}

export interface SurveyClient {
  /** Get active survey for current user (if any) */
  getActiveSurvey(): Promise<{ survey: ActiveSurvey | null }>;
  /** Start a survey session */
  startSurvey(surveyId: string): Promise<{
    responseId: string;
    startedAt: string;
    currentQuestionIndex: number;
    answers: Record<string, QuestionAnswer>;
  }>;
  /** Submit an answer */
  submitAnswer(
    surveyId: string,
    questionId: string,
    answer: QuestionAnswer
  ): Promise<{
    responseId: string;
    currentQuestionIndex: number;
    answers: Record<string, QuestionAnswer>;
  }>;
  /** Complete the survey */
  completeSurvey(surveyId: string): Promise<{
    success: boolean;
    timeSpentSeconds: number;
    incentiveClaimed: boolean;
  }>;
  /** Dismiss survey (won't show again) */
  dismissSurvey(surveyId: string): Promise<void>;
  /** Check for eligible surveys periodically */
  pollSurveys(intervalMs?: number): () => void;
  /** Get cached response for a survey (for offline support) */
  getCachedResponse(surveyId: string): SurveyResponse | null;
  /** Save response to cache */
  cacheResponse(surveyId: string, response: Partial<SurveyResponse>): void;
}

export function createSurveyClient(config: SurveyClientConfig): SurveyClient {
  const headers = async () => ({
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${await Promise.resolve(config.getAuthToken())}`,
    'x-product-id': config.productId,
    'x-platform': config.platform,
    'x-app-version': config.appVersion,
    'x-os-version': config.osVersion,
    ...(config.countryCode && { 'x-country-code': config.countryCode }),
    ...(config.regionCode && { 'x-region-code': config.regionCode }),
    'x-user-segments': (config.userSegments ?? ['free']).join(','),
    ...(config.deviceId && { 'x-device-id': config.deviceId }),
  });

  const request = async <T>(path: string, options?: RequestInit): Promise<T> => {
    const res = await fetch(`${config.baseUrl}${path}`, {
      ...options,
      headers: {
        ...(await headers()),
        ...(options?.headers || {}),
      },
    });
    if (!res.ok) {
      const err = await res.text();
      throw new Error(`Survey API error: ${res.status} ${err}`);
    }
    return res.json() as Promise<T>;
  };

  // In-memory cache for offline support
  const responseCache = new Map<string, SurveyResponse>();

  let pollInterval: ReturnType<typeof setInterval> | null = null;

  return {
    async getActiveSurvey() {
      return request<{ survey: ActiveSurvey | null }>('/surveys/active');
    },

    async startSurvey(surveyId: string) {
      const result = await request<{
        responseId: string;
        startedAt: string;
        currentQuestionIndex: number;
        answers: Record<string, QuestionAnswer>;
      }>(`/surveys/${surveyId}/start`, { method: 'POST' });
      // Cache the initial response
      this.cacheResponse(surveyId, {
        id: result.responseId,
        surveyId,
        userId: '', // Will be filled by server
        answers: result.answers,
        currentQuestionIndex: result.currentQuestionIndex,
        startedAt: result.startedAt,
        isComplete: false,
        incentiveClaimed: false,
        createdAt: result.startedAt,
        updatedAt: result.startedAt,
      });
      return result;
    },

    async submitAnswer(surveyId: string, questionId: string, answer: QuestionAnswer) {
      const result = await request<{
        responseId: string;
        currentQuestionIndex: number;
        answers: Record<string, QuestionAnswer>;
      }>(`/surveys/${surveyId}/response`, {
        method: 'POST',
        body: JSON.stringify({ questionId, answer }),
      });
      // Update cache
      const cached = responseCache.get(surveyId);
      if (cached) {
        cached.answers = result.answers;
        cached.currentQuestionIndex = result.currentQuestionIndex;
        cached.updatedAt = new Date().toISOString();
      }
      return result;
    },

    async completeSurvey(surveyId: string) {
      const result = await request<{
        success: boolean;
        timeSpentSeconds: number;
        incentiveClaimed: boolean;
      }>(`/surveys/${surveyId}/complete`, { method: 'POST' });
      // Clear cache on completion
      responseCache.delete(surveyId);
      return result;
    },

    async dismissSurvey(surveyId: string) {
      await request<void>(`/surveys/${surveyId}/dismiss`, { method: 'POST' });
      responseCache.delete(surveyId);
    },

    pollSurveys(intervalMs = 60000) {
      if (pollInterval) clearInterval(pollInterval);
      pollInterval = setInterval(() => {
        this.getActiveSurvey().catch(() => {});
      }, intervalMs);
      return () => {
        if (pollInterval) {
          clearInterval(pollInterval);
          pollInterval = null;
        }
      };
    },

    getCachedResponse(surveyId: string) {
      return responseCache.get(surveyId) ?? null;
    },

    cacheResponse(surveyId: string, response: Partial<SurveyResponse>) {
      const existing = responseCache.get(surveyId);
      responseCache.set(surveyId, {
        ...existing,
        ...response,
      } as SurveyResponse);
    },
  };
}

// =============================================================================
// Answer Validation
// =============================================================================

export function validateAnswer(
  question: Question,
  answer: QuestionAnswer
): { valid: boolean; error?: string } {
  // Type matching
  const expectedType = question.type === 'dropdown' ? 'single_choice' :
                       question.type === 'scale' ? 'rating' :
                       question.type === 'text_short' || question.type === 'text_long' ? 'text' :
                       question.type;
  
  if (answer.type !== expectedType) {
    return { valid: false, error: `Expected ${expectedType}, got ${answer.type}` };
  }

  // Value range validation
  if (answer.type === 'rating' || answer.type === 'nps') {
    if (question.minValue !== undefined && answer.value < question.minValue) {
      return { valid: false, error: `Value below minimum ${question.minValue}` };
    }
    if (question.maxValue !== undefined && answer.value > question.maxValue) {
      return { valid: false, error: `Value above maximum ${question.maxValue}` };
    }
  }

  // Text length validation
  if (answer.type === 'text') {
    if (question.minLength !== undefined && answer.value.length < question.minLength) {
      return { valid: false, error: `Text too short (min ${question.minLength})` };
    }
    if (question.maxLength !== undefined && answer.value.length > question.maxLength) {
      return { valid: false, error: `Text too long (max ${question.maxLength})` };
    }
  }

  return { valid: true };
}

// =============================================================================
// React Hook (optional)
// =============================================================================

export function createUseSurvey(client: SurveyClient) {
  return function useSurvey() {
    return { client };
  };
}
