/**
 * Survey module tests — schema validation and answer validation.
 */

import { describe, it, expect } from 'vitest';
import {
  CreateSurveySchema,
  UpdateSurveySchema,
  SubmitAnswerSchema,
  QuestionSchema,
  computeCompletionRate,
  validateAnswerType,
  type Question,
  type QuestionAnswer,
  type SurveyMetrics,
} from './types.js';

// ── Schema validation ──

describe('CreateSurveySchema', () => {
  it('validates minimal survey', () => {
    const result = CreateSurveySchema.safeParse({
      title: 'User Feedback',
      questions: [
        { id: 'q1', type: 'nps', text: 'How likely are you to recommend?', required: true },
      ],
      displayTrigger: { type: 'immediate' },
    });
    expect(result.success).toBe(true);
  });

  it('rejects empty questions', () => {
    const result = CreateSurveySchema.safeParse({
      title: 'Bad Survey',
      questions: [],
      displayTrigger: { type: 'immediate' },
    });
    expect(result.success).toBe(false);
  });

  it('validates survey with all trigger types', () => {
    for (const trigger of [
      { type: 'immediate' as const },
      { type: 'delay_seconds' as const, seconds: 30 },
      { type: 'event' as const, eventName: 'purchase_complete' },
      { type: 'page_view' as const, pagePattern: '/settings*' },
    ]) {
      const result = CreateSurveySchema.safeParse({
        title: 'Test',
        questions: [{ id: 'q1', type: 'nps', text: 'Rate us', required: true }],
        displayTrigger: trigger,
      });
      expect(result.success).toBe(true);
    }
  });

  it('validates survey with incentive', () => {
    const result = CreateSurveySchema.safeParse({
      title: 'Feedback',
      questions: [{ id: 'q1', type: 'text_short', text: 'Any thoughts?', required: false }],
      displayTrigger: { type: 'immediate' },
      incentive: { type: 'pro_days', amount: 7 },
    });
    expect(result.success).toBe(true);
  });
});

describe('UpdateSurveySchema', () => {
  it('allows partial updates', () => {
    expect(UpdateSurveySchema.safeParse({ title: 'New Title' }).success).toBe(true);
  });

  it('allows status change', () => {
    expect(UpdateSurveySchema.safeParse({ status: 'closed' }).success).toBe(true);
  });
});

describe('QuestionSchema', () => {
  it('validates single choice question with options', () => {
    const result = QuestionSchema.safeParse({
      id: 'q1',
      type: 'single_choice',
      text: 'Pick one',
      required: true,
      options: [
        { id: 'o1', text: 'Option A' },
        { id: 'o2', text: 'Option B' },
      ],
    });
    expect(result.success).toBe(true);
  });

  it('validates question with conditional logic', () => {
    const result = QuestionSchema.safeParse({
      id: 'q2',
      type: 'text_short',
      text: 'Why?',
      required: false,
      showIf: { questionId: 'q1', operator: 'equals', value: 'o1' },
    });
    expect(result.success).toBe(true);
  });
});

describe('SubmitAnswerSchema', () => {
  it('validates NPS answer', () => {
    const result = SubmitAnswerSchema.safeParse({
      questionId: 'q1',
      answer: { type: 'nps', value: 9 },
    });
    expect(result.success).toBe(true);
  });

  it('validates text answer', () => {
    const result = SubmitAnswerSchema.safeParse({
      questionId: 'q2',
      answer: { type: 'text', value: 'Great app!' },
    });
    expect(result.success).toBe(true);
  });

  it('validates ranking answer', () => {
    const result = SubmitAnswerSchema.safeParse({
      questionId: 'q3',
      answer: { type: 'ranking', rankedOptionIds: ['o2', 'o1', 'o3'] },
    });
    expect(result.success).toBe(true);
  });

  it('rejects NPS value out of range', () => {
    const result = SubmitAnswerSchema.safeParse({
      questionId: 'q1',
      answer: { type: 'nps', value: 11 },
    });
    expect(result.success).toBe(false);
  });
});

// ── Helper functions ──

describe('computeCompletionRate', () => {
  it('computes rate correctly', () => {
    const metrics: SurveyMetrics = {
      impressions: 100,
      starts: 50,
      completions: 25,
      avgTimeSeconds: 60,
      incentiveClaims: 10,
    };
    expect(computeCompletionRate(metrics)).toBe(0.5);
  });

  it('returns 0 when no starts', () => {
    const metrics: SurveyMetrics = {
      impressions: 0,
      starts: 0,
      completions: 0,
      avgTimeSeconds: 0,
      incentiveClaims: 0,
    };
    expect(computeCompletionRate(metrics)).toBe(0);
  });
});

describe('validateAnswerType', () => {
  it('validates matching answer type', () => {
    const question: Question = { id: 'q1', type: 'nps', text: 'Rate us', required: true };
    const answer: QuestionAnswer = { type: 'nps', value: 8 };
    expect(validateAnswerType(question, answer)).toEqual({ valid: true });
  });

  it('rejects mismatched answer type', () => {
    const question: Question = { id: 'q1', type: 'nps', text: 'Rate us', required: true };
    const answer: QuestionAnswer = { type: 'text', value: 'hello' };
    const result = validateAnswerType(question, answer);
    expect(result.valid).toBe(false);
    expect(result.error).toContain('Expected nps');
  });

  it('validates text length constraints', () => {
    const question: Question = {
      id: 'q1',
      type: 'text_short',
      text: 'Name?',
      required: true,
      minLength: 2,
      maxLength: 50,
    };
    expect(validateAnswerType(question, { type: 'text', value: 'A' }).valid).toBe(false);
    expect(validateAnswerType(question, { type: 'text', value: 'Alice' }).valid).toBe(true);
  });

  it('validates rating range constraints', () => {
    const question: Question = {
      id: 'q1',
      type: 'rating',
      text: 'Rate',
      required: true,
      minValue: 1,
      maxValue: 5,
    };
    expect(validateAnswerType(question, { type: 'rating', value: 0 }).valid).toBe(false);
    expect(validateAnswerType(question, { type: 'rating', value: 3 }).valid).toBe(true);
    expect(validateAnswerType(question, { type: 'rating', value: 6 }).valid).toBe(false);
  });

  it('treats dropdown as single_choice', () => {
    const question: Question = { id: 'q1', type: 'dropdown', text: 'Pick', required: true };
    expect(validateAnswerType(question, { type: 'single_choice', optionId: 'o1' }).valid).toBe(
      true
    );
    expect(validateAnswerType(question, { type: 'text', value: 'bad' }).valid).toBe(false);
  });

  it('treats scale as rating', () => {
    const question: Question = { id: 'q1', type: 'scale', text: 'How much?', required: true };
    expect(validateAnswerType(question, { type: 'rating', value: 5 }).valid).toBe(true);
  });
});
