import { describe, it, expect, beforeEach, vi } from 'vitest';
import { SMSClassifierService } from '../services/spamshield/spamshield.service';

// Mock shared-db before anything else (Prisma client is not generated in test env)
vi.mock('@shieldsai/shared-db', () => ({
  prisma: {},
  SpamFeedback: {},
}));

// Mock the feature flags module to control enableMLClassifier
vi.mock('../services/spamshield/spamshield.config', () => ({
  spamShieldEnv: {
    SPAM_THRESHOLD_AUTO_BLOCK: 0.85,
    SPAM_THRESHOLD_FLAG: 0.6,
  },
  spamFeatureFlags: {
    enableMLClassifier: true,
  },
  SpamDecision: {
    ALLOW: 'allow',
    FLAG: 'flag',
    BLOCK: 'block',
    CHALLENGE: 'challenge',
  },
  SpamLayer: {
    NUMBER_REPUTATION: 'number_reputation',
    CONTENT_CLASSIFICATION: 'content_classification',
    BEHAVIORAL_ANALYSIS: 'behavioral_analysis',
    COMMUNITY_INTELLIGENCE: 'community_intelligence',
  },
  ConfidenceLevel: {
    LOW: 'low',
    MEDIUM: 'medium',
    HIGH: 'high',
    VERY_HIGH: 'very_high',
  },
  spamRateLimits: {},
}));

describe('SMSClassifierService', () => {
  let classifier: SMSClassifierService;
  let initializeCalls: number;
  let initializeDelay: Promise<void>;

  beforeEach(() => {
    // Re-import after mock to get fresh module state
    initializeCalls = 0;
    initializeDelay = new Promise(resolve => setTimeout(resolve, 50));

    classifier = new SMSClassifierService();
    // Override initialize to track calls and add delay
    classifier.initialize = async () => {
      initializeCalls++;
      await initializeDelay;
    };
  });

  describe('initialization race condition', () => {
    it('should call initialize only once under concurrent classify calls', async () => {
      const promises = Array.from({ length: 10 }, () =>
        classifier.classify('ACT NOW - Limited offer!'),
      );

      const results = await Promise.all(promises);

      expect(initializeCalls).toBe(1);
      expect(results).toHaveLength(10);
      results.forEach(r => {
        expect(r).toHaveProperty('isSpam');
        expect(r).toHaveProperty('confidence');
        expect(r).toHaveProperty('spamFeatures');
      });
    });

    it('should handle interleaved calls after partial initialization', async () => {
      const batch1 = Array.from({ length: 5 }, () =>
        classifier.classify('First batch message'),
      );

      await Promise.all(batch1);

      expect(initializeCalls).toBe(1);

      const batch2 = Array.from({ length: 5 }, () =>
        classifier.classify('Second batch message'),
      );

      await Promise.all(batch2);

      // initialize should still only have been called once
      expect(initializeCalls).toBe(1);
    });

    it('should return consistent results for same input under concurrency', async () => {
      const text = 'URGENT: Click http://example.com now!';
      const promises = Array.from({ length: 20 }, () =>
        classifier.classify(text),
      );

      const results = await Promise.all(promises);

      const firstResult = results[0];
      results.forEach((r, i) => {
        expect(r.isSpam).toBe(firstResult.isSpam);
        expect(r.confidence).toBe(firstResult.confidence);
        expect(r.spamFeatures).toEqual(firstResult.spamFeatures);
      });
    });

    it('should handle rapid sequential calls without re-initializing', async () => {
      for (let i = 0; i < 50; i++) {
        await classifier.classify(`Message ${i}`);
      }

      expect(initializeCalls).toBe(1);
    });
  });

  describe('feature extraction', () => {
    it('should detect URL presence', async () => {
      const result = await classifier.classify('Visit www.example.com');
      expect(result.spamFeatures).toContain('url_present');
    });

    it('should detect urgency keywords', async () => {
      const result = await classifier.classify('Act now! This offer is urgent.');
      expect(result.spamFeatures).toContain('urgency_keyword');
    });

    it('should detect excessive capitalization', async () => {
      const result = await classifier.classify('BUY THIS NOW!!!');
      expect(result.spamFeatures).toContain('excessive_caps');
    });

    it('should detect multiple features', async () => {
      const result = await classifier.classify(
        'URGENT: Visit www.example.com NOW!!!',
      );
      expect(result.spamFeatures).toContain('url_present');
      expect(result.spamFeatures).toContain('urgency_keyword');
      expect(result.spamFeatures).toContain('excessive_caps');
    });
  });
});
