/**
 * Marketplace module unit tests — validates schema parsing and type guards.
 * Tests: listings, reviews, installs, certifications, reports.
 */

import { describe, it, expect } from 'vitest';
import {
  CreateListingSchema,
  UpdateListingSchema,
  SubmitForCertificationSchema,
  CertificationActionSchema,
  ListListingsQuerySchema,
  CreateReviewSchema,
  UpdateReviewSchema,
  ListReviewsQuerySchema,
  ListInstallsQuerySchema,
  CreateReportSchema,
  ResolveReportSchema,
  ListReportsQuerySchema,
  CERTIFICATION_STATUSES,
  PRICING_MODELS,
  VISIBILITY_LEVELS,
  REPORT_REASONS,
  REPORT_STATUSES,
} from './types.js';

// ─────────────────────────────────────────────────────────────────────────────
// Listing Schemas
// ─────────────────────────────────────────────────────────────────────────────

describe('CreateListingSchema', () => {
  it('accepts valid listing input', () => {
    const result = CreateListingSchema.safeParse({
      templateType: 'agent',
      title: 'FAANG Interview Prep Coach',
      shortDescription: 'Practice technical interviews with AI',
      description: 'Full description here',
      tags: ['interview', 'career'],
      category: 'career',
      payload: { systemPrompt: 'You are a coach...' },
    });
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.templateType).toBe('agent');
      expect(result.data.pricingModel).toBe('free');
      expect(result.data.visibility).toBe('private');
      expect(result.data.priceInCents).toBe(0);
    }
  });

  it('accepts paid listing', () => {
    const result = CreateListingSchema.safeParse({
      templateType: 'agent',
      title: 'Premium Coach',
      shortDescription: 'Premium coaching',
      description: 'Full description',
      tags: [],
      category: 'career',
      payload: { premium: true },
      pricingModel: 'paid',
      priceInCents: 499,
    });
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.pricingModel).toBe('paid');
      expect(result.data.priceInCents).toBe(499);
    }
  });

  it('rejects missing title', () => {
    const result = CreateListingSchema.safeParse({
      templateType: 'agent',
      shortDescription: 'Test',
      description: 'Test',
    });
    expect(result.success).toBe(false);
  });

  it('rejects too many tags', () => {
    const result = CreateListingSchema.safeParse({
      templateType: 'agent',
      title: 'Test',
      shortDescription: 'Test',
      description: 'Test',
      tags: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'],
    });
    expect(result.success).toBe(false);
  });

  it('rejects invalid pricing model', () => {
    const result = CreateListingSchema.safeParse({
      templateType: 'agent',
      title: 'Test',
      shortDescription: 'Test',
      description: 'Test',
      pricingModel: 'subscription',
    });
    expect(result.success).toBe(false);
  });

  it('rejects invalid visibility', () => {
    const result = CreateListingSchema.safeParse({
      templateType: 'agent',
      title: 'Test',
      shortDescription: 'Test',
      description: 'Test',
      visibility: 'secret',
    });
    expect(result.success).toBe(false);
  });
});

describe('UpdateListingSchema', () => {
  it('accepts partial updates', () => {
    const result = UpdateListingSchema.safeParse({ title: 'New title' });
    expect(result.success).toBe(true);
  });

  it('accepts empty object', () => {
    const result = UpdateListingSchema.safeParse({});
    expect(result.success).toBe(true);
  });

  it('rejects invalid pricing model', () => {
    const result = UpdateListingSchema.safeParse({ pricingModel: 'invalid' });
    expect(result.success).toBe(false);
  });
});

describe('SubmitForCertificationSchema', () => {
  it('accepts empty submission', () => {
    const result = SubmitForCertificationSchema.safeParse({});
    expect(result.success).toBe(true);
  });

  it('accepts submission with notes', () => {
    const result = SubmitForCertificationSchema.safeParse({
      notes: 'Please review promptly',
    });
    expect(result.success).toBe(true);
  });

  it('rejects notes too long', () => {
    const result = SubmitForCertificationSchema.safeParse({
      notes: 'a'.repeat(1001),
    });
    expect(result.success).toBe(false);
  });
});

describe('CertificationActionSchema', () => {
  it('accepts approve action with notes', () => {
    const result = CertificationActionSchema.safeParse({
      notes: 'Looks good',
      automatedChecks: {
        promptSafety: 'pass',
        contentPolicy: 'pass',
        payloadValid: true,
        screenshotCount: 2,
      },
    });
    expect(result.success).toBe(true);
  });

  it('accepts reject action with notes only', () => {
    const result = CertificationActionSchema.safeParse({
      notes: 'Needs more screenshots',
    });
    expect(result.success).toBe(true);
  });

  it('rejects invalid prompt safety value', () => {
    const result = CertificationActionSchema.safeParse({
      automatedChecks: {
        promptSafety: 'ok',
        contentPolicy: 'pass',
        payloadValid: true,
        screenshotCount: 1,
      },
    });
    expect(result.success).toBe(false);
  });
});

describe('ListListingsQuerySchema', () => {
  it('provides defaults for empty query', () => {
    const result = ListListingsQuerySchema.safeParse({});
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.sortBy).toBe('createdAt');
      expect(result.data.sortOrder).toBe('desc');
      expect(result.data.limit).toBe(20);
      expect(result.data.offset).toBe(0);
    }
  });

  it('accepts valid sort options', () => {
    const sortOptions = ['installCount', 'rating', 'newest', 'trending', 'createdAt'];
    for (const sortBy of sortOptions) {
      const result = ListListingsQuerySchema.safeParse({ sortBy });
      expect(result.success).toBe(true);
    }
  });

  it('accepts minRating filter', () => {
    const result = ListListingsQuerySchema.safeParse({ minRating: 4 });
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.minRating).toBe(4);
    }
  });

  it('rejects minRating > 5', () => {
    const result = ListListingsQuerySchema.safeParse({ minRating: 6 });
    expect(result.success).toBe(false);
  });

  it('accepts comma-separated tags', () => {
    const result = ListListingsQuerySchema.safeParse({ tags: 'interview,career,tech' });
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.tags).toBe('interview,career,tech');
    }
  });
});

// ─────────────────────────────────────────────────────────────────────────────
// Review Schemas
// ─────────────────────────────────────────────────────────────────────────────

describe('CreateReviewSchema', () => {
  it('accepts valid review', () => {
    const result = CreateReviewSchema.safeParse({
      rating: 5,
      title: 'Excellent template!',
      body: 'This helped me prepare for my interviews. Highly recommended.',
    });
    expect(result.success).toBe(true);
  });

  it('accepts 1-star review', () => {
    const result = CreateReviewSchema.safeParse({
      rating: 1,
      title: 'Not helpful',
      body: 'Did not meet expectations',
    });
    expect(result.success).toBe(true);
  });

  it('rejects rating 0', () => {
    const result = CreateReviewSchema.safeParse({
      rating: 0,
      title: 'Test',
      body: 'Test',
    });
    expect(result.success).toBe(false);
  });

  it('rejects rating > 5', () => {
    const result = CreateReviewSchema.safeParse({
      rating: 6,
      title: 'Test',
      body: 'Test',
    });
    expect(result.success).toBe(false);
  });

  it('rejects missing title', () => {
    const result = CreateReviewSchema.safeParse({
      rating: 4,
      body: 'Good',
    });
    expect(result.success).toBe(false);
  });

  it('rejects body too long', () => {
    const result = CreateReviewSchema.safeParse({
      rating: 4,
      title: 'Test',
      body: 'a'.repeat(2001),
    });
    expect(result.success).toBe(false);
  });
});

describe('UpdateReviewSchema', () => {
  it('accepts partial updates', () => {
    const result = UpdateReviewSchema.safeParse({ rating: 3 });
    expect(result.success).toBe(true);
  });

  it('accepts empty object', () => {
    const result = UpdateReviewSchema.safeParse({});
    expect(result.success).toBe(true);
  });
});

describe('ListReviewsQuerySchema', () => {
  it('provides defaults', () => {
    const result = ListReviewsQuerySchema.safeParse({});
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.sortBy).toBe('newest');
      expect(result.data.verifiedOnly).toBe(false);
    }
  });

  it('accepts verifiedOnly filter', () => {
    const result = ListReviewsQuerySchema.safeParse({ verifiedOnly: true });
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.verifiedOnly).toBe(true);
    }
  });
});

// ─────────────────────────────────────────────────────────────────────────────
// Install Schemas
// ─────────────────────────────────────────────────────────────────────────────

describe('ListInstallsQuerySchema', () => {
  it('provides defaults', () => {
    const result = ListInstallsQuerySchema.safeParse({});
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.limit).toBe(20);
      expect(result.data.offset).toBe(0);
    }
  });

  it('accepts productId filter', () => {
    const result = ListInstallsQuerySchema.safeParse({ productId: 'jarvisjr' });
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.productId).toBe('jarvisjr');
    }
  });
});

// ─────────────────────────────────────────────────────────────────────────────
// Report Schemas
// ─────────────────────────────────────────────────────────────────────────────

describe('CreateReportSchema', () => {
  it('accepts valid report', () => {
    const result = CreateReportSchema.safeParse({
      reason: 'spam',
      details: 'This listing is spam',
    });
    expect(result.success).toBe(true);
  });

  it('accepts all valid reasons', () => {
    const reasons = ['spam', 'harmful', 'misleading', 'copyright', 'inappropriate', 'other'];
    for (const reason of reasons) {
      const result = CreateReportSchema.safeParse({
        reason,
        details: 'Report details',
      });
      expect(result.success).toBe(true);
    }
  });

  it('rejects invalid reason', () => {
    const result = CreateReportSchema.safeParse({
      reason: 'invalid',
      details: 'Test',
    });
    expect(result.success).toBe(false);
  });

  it('rejects missing details', () => {
    const result = CreateReportSchema.safeParse({
      reason: 'spam',
    });
    expect(result.success).toBe(false);
  });
});

describe('ResolveReportSchema', () => {
  it('accepts resolve action', () => {
    const result = ResolveReportSchema.safeParse({
      status: 'resolved',
      resolutionNotes: 'Issue addressed',
    });
    expect(result.success).toBe(true);
  });

  it('accepts dismiss action', () => {
    const result = ResolveReportSchema.safeParse({ status: 'dismissed' });
    expect(result.success).toBe(true);
  });

  it('rejects open status', () => {
    const result = ResolveReportSchema.safeParse({ status: 'open' });
    expect(result.success).toBe(false);
  });
});

describe('ListReportsQuerySchema', () => {
  it('provides defaults', () => {
    const result = ListReportsQuerySchema.safeParse({});
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.limit).toBe(20);
    }
  });

  it('accepts status filter', () => {
    const result = ListReportsQuerySchema.safeParse({ status: 'open' });
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.status).toBe('open');
    }
  });
});

// ─────────────────────────────────────────────────────────────────────────────
// Type Constants
// ─────────────────────────────────────────────────────────────────────────────

describe('type constants', () => {
  it('has expected certification statuses', () => {
    expect(CERTIFICATION_STATUSES).toEqual([
      'draft',
      'submitted',
      'in_review',
      'approved',
      'rejected',
      'suspended',
    ]);
  });

  it('has expected pricing models', () => {
    expect(PRICING_MODELS).toEqual(['free', 'paid', 'freemium']);
  });

  it('has expected visibility levels', () => {
    expect(VISIBILITY_LEVELS).toEqual(['private', 'unlisted', 'public']);
  });

  it('has expected report reasons', () => {
    expect(REPORT_REASONS).toEqual([
      'spam',
      'harmful',
      'misleading',
      'copyright',
      'inappropriate',
      'other',
    ]);
  });

  it('has expected report statuses', () => {
    expect(REPORT_STATUSES).toEqual(['open', 'resolved', 'dismissed']);
  });
});
