/**
 * contentSecurityService.test.js
 * Unit tests for server-side content security service.
 */

const { describe, it, before, after, beforeEach } = require('node:test');
const assert = require('node:assert/strict');

const ContentSecurityService = require('../services/contentSecurityService');

describe('ContentSecurityService', () => {
  let service;

  before(() => {
    service = new ContentSecurityService();
  });

  after(() => {
    // Clean up rate limiter state
    service._requestTimestamps = [];
    service._requestQueue.forEach(resolve => resolve());
    service._requestQueue = [];
    service._isProcessingQueue = false;
  });

  it('should initialize with rate limiter', () => {
    assert.ok(service._requestTimestamps);
    assert.ok(Array.isArray(service._requestTimestamps));
    assert.ok(service._requestQueue);
    assert.ok(Array.isArray(service._requestQueue));
  });

  it('should have checkTextContent method', () => {
    assert.strictEqual(typeof service.checkTextContent, 'function');
  });

  it('should have checkImageContent method', () => {
    assert.strictEqual(typeof service.checkImageContent, 'function');
  });

  it('should reject checkTextContent when token manager is unavailable', async () => {
    // Override token manager to be unavailable
    if (service.tokenManager) {
      service.tokenManager._accessToken = '';
      service.tokenManager._isAvailable = false;
    }

    try {
      const result = await service.checkTextContent('test_openid', 'hello', 1);
      // When token is unavailable, should return error or risky
      assert.ok(result);
      assert.strictEqual(result.pass, false);
    } catch (e) {
      // Also acceptable - throws when service unavailable
      assert.ok(e);
    }
  });

  it('should respect rate limiting', async () => {
    // Test rate limiter concept
    const now = Date.now();
    service._requestTimestamps = [];

    // Should allow first request
    await service._enforceRateLimit();
    assert.ok(service._requestTimestamps.length > 0);

    // Fill up rate limit
    for (let i = 0; i < 5000; i++) {
      service._requestTimestamps.push(now);
    }

    // Should queue when limit reached (returns a pending Promise)
    const limited = service._enforceRateLimit();
    assert.ok(limited instanceof Promise);
    // Clean up: clear the queue to avoid hanging
    service._requestQueue.forEach(resolve => resolve());
    service._requestQueue = [];
    service._requestTimestamps = [];
    service._isProcessingQueue = false;
  });
});

describe('ViolationService', () => {
  let violationService;

  before(() => {
    const ViolationService = require('../services/violationService');
    const AuditLogger = require('../services/auditLogger');
    violationService = new ViolationService({ logger: new AuditLogger() });
  });

  after(() => {
    // Clean up any timers using destroy method
    if (violationService.destroy) {
      violationService.destroy();
    }
  });

  it('should initialize without errors', () => {
    assert.ok(violationService);
  });

  it('should have recordViolation method', () => {
    assert.strictEqual(typeof violationService.recordViolation, 'function');
  });

  it('should have getMuteStatus method', () => {
    assert.strictEqual(typeof violationService.getMuteStatus, 'function');
  });

  it('should record a violation and increment count', () => {
    const testUserId = 'test_user_' + Date.now();
    violationService.recordViolation({
      userId: testUserId,
      violationType: 'text_violation',
      contentSummary: '测试违规内容',
      scene: 2,
    });

    const status = violationService.getMuteStatus(testUserId);
    assert.ok(status);
    assert.strictEqual(typeof status.isMuted, 'boolean');
    // Check violation count via internal records
    const record = violationService._records.get(testUserId);
    assert.ok(record);
    assert.strictEqual(typeof record.count, 'number');
    assert.strictEqual(record.count, 1);
  });

  it('should apply mute penalty at 3 violations', () => {
    const testUserId = 'mute_test_' + Date.now();

    // Record 3 violations
    for (let i = 0; i < 3; i++) {
      violationService.recordViolation({
        userId: testUserId,
        violationType: 'pornography',
        contentSummary: `violation ${i}`,
        scene: 2,
      });
    }

    const status = violationService.getMuteStatus(testUserId);
    assert.strictEqual(status.isMuted, true);
    assert.ok(status.remainingMs > 0);
  });

  it('should escalate mute at 5 violations', () => {
    const testUserId = 'escalate_test_' + Date.now();

    // Record 5 violations
    for (let i = 0; i < 5; i++) {
      violationService.recordViolation({
        userId: testUserId,
        violationType: 'gambling',
        contentSummary: `violation ${i}`,
        scene: 2,
      });
    }

    const status = violationService.getMuteStatus(testUserId);
    assert.strictEqual(status.isMuted, true);
  });
});

describe('ReportService', () => {
  let reportService;

  before(() => {
    const ReportService = require('../services/reportService');
    const AuditLogger = require('../services/auditLogger');
    reportService = new ReportService({ logger: new AuditLogger() });
  });

  it('should initialize without errors', () => {
    assert.ok(reportService);
  });

  it('should have submitReport method', () => {
    assert.strictEqual(typeof reportService.submitReport, 'function');
  });

  it('should accept a report submission', () => {
    const result = reportService.submitReport({
      contentId: 'test_content_' + Date.now(),
      targetUserId: 'target_user_123',
      contentType: 'chat',
      contentSummary: 'test content',
      reporterId: 'reporter_user_456',
      reason: 'politics',
    });

    assert.ok(result);
    assert.strictEqual(typeof result.success, 'boolean');
  });
});
