import React from 'react';
import { updateCharCount, checkUnicode } from '../smsCharCountV2';
import * as Api from '../../services/api';

jest.mock('../../services/api');

describe('smsCharCountV2', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    // Setup default mock to return resolved promise
    Api.getUnsubscribeUrl.mockResolvedValue({
      response: { response: '' },
    });
  });

  describe('checkUnicode', () => {
    it('should return false for 7-bit ASCII characters', () => {
      const result = checkUnicode('Hello');
      expect(result).toBe(false);
    });

    it('should return true for Unicode characters', () => {
      const result = checkUnicode('你好');
      expect(result).toBe(true);
    });

    it('should return false for empty string', () => {
      const result = checkUnicode('');
      expect(result).toBe(false);
    });

    it('should return false for 7-bit extended characters', () => {
      const result = checkUnicode('\f^{}');
      expect(result).toBe(false);
    });

    it('should return true when mixed with Unicode', () => {
      const result = checkUnicode('Hello世界');
      expect(result).toBe(true);
    });

    it('should return false for special 7-bit GSM characters', () => {
      const result = checkUnicode('@£$¥');
      expect(result).toBe(false);
    });

    it('should return false for escape sequences', () => {
      const result = checkUnicode('\\[~]|€');
      expect(result).toBe(false);
    });
  });

  describe('updateCharCount', () => {
    it('should return basic SMS details for simple 7-bit message', () => {
      const result = updateCharCount('Hello');
      expect(result).toHaveProperty('unicode', false);
      expect(result).toHaveProperty('parts', 1);
      expect(result).toHaveProperty('chars_sms', 160);
      expect(result).toHaveProperty('optoutUrlPresent', false);
    });

    it('should return SMS details for simple Unicode message', () => {
      const result = updateCharCount('你好');
      expect(result.unicode).toBe(true);
      expect(result.parts).toBe(1);
      expect(result.chars_sms).toBe(70);
    });

    it('should detect 7-bit messages up to 160 characters', () => {
      const msg = 'A'.repeat(160);
      const result = updateCharCount(msg);
      expect(result.unicode).toBe(false);
      expect(result.parts).toBe(1);
      expect(result.chars_sms).toBe(160);
    });

    it('should calculate multipart for 7-bit messages over 160 chars', () => {
      const msg = 'A'.repeat(161);
      const result = updateCharCount(msg);
      expect(result.unicode).toBe(false);
      expect(result.parts).toBe(2);
      expect(result.chars_sms).toBe(153);
    });

    it('should calculate correct parts for large 7-bit messages', () => {
      const msg = 'A'.repeat(500);
      const result = updateCharCount(msg);
      expect(result.unicode).toBe(false);
      expect(result.parts).toBe(Math.ceil(500 / 153));
    });

    it('should detect Unicode messages up to 70 characters', () => {
      const msg = '你'.repeat(70);
      const result = updateCharCount(msg);
      expect(result.unicode).toBe(true);
      expect(result.parts).toBe(1);
      expect(result.chars_sms).toBe(70);
    });

    it('should calculate multipart for Unicode messages over 70 chars', () => {
      const msg = '你'.repeat(71);
      const result = updateCharCount(msg);
      expect(result.unicode).toBe(true);
      expect(result.parts).toBe(2);
      expect(result.chars_sms).toBe(67);
    });

    it('should handle message with optout tag', () => {
      const result = updateCharCount('Hello{{optout}}');
      expect(result.optoutUrlPresent).toBe(true);
      expect(result.parts).toBe(1);
    });

    it('should handle message without optout tag', () => {
      const res = updateCharCount('Hello');
      expect(res.optoutUrlPresent).toBe(false);
      expect(res.parts).toBe(1);
    });

    it('should handle multiple optout tags', () => {
      const result = updateCharCount('Hello{{optout}}World{{optout}}');
      expect(result.optoutUrlPresent).toBe(true);
    });

    it('should handle default empty string parameter', () => {
      const result = updateCharCount();
      expect(result.chars_used).toBe(0);
      expect(result.parts).toBe(1);
    });

    it('should count 7-bit extended characters as 2 bytes', () => {
      const result = updateCharCount('A\fB'); // \f is 2-byte GSM-7 character
      expect(result.unicode).toBe(false);
      expect(result.char_list).toBeDefined();
    });

    it('should handle isUnicodeEnabled parameter', () => {
      const result = updateCharCount('Hello', true);
      expect(result).toBeDefined();
    });

    it('should handle isUnicodeEnabled as false', () => {
      const result = updateCharCount('Hello', false);
      expect(result).toBeDefined();
    });

    it('should return char_list with React elements', () => {
      const result = updateCharCount('Hi');
      expect(Array.isArray(result.char_list)).toBe(true);
      expect(result.char_list.length).toBe(2);
    });

    it('should include responseState in return object', () => {
      const result = updateCharCount('Test');
      expect(result).toHaveProperty('responseState');
    });

    it('should handle optout URL when available from API', () => {
      Api.getUnsubscribeUrl.mockResolvedValueOnce({
        response: { response: 'https://example.com/unsub' },
      });

      const result = updateCharCount('Hello{{optout}}');
      expect(result.optoutUrlPresent).toBe(true);
    });

    it('should handle API error gracefully', () => {
      Api.getUnsubscribeUrl.mockRejectedValueOnce(new Error('API failed'));

      const result = updateCharCount('Hello{{optout}}');
      expect(result).toBeDefined();
    });

    it('should calculate correct char count with 7-bit extended chars', () => {
      const result = updateCharCount('Test[Message]');
      expect(result.unicode).toBe(false);
    });

    it('should handle all GSM-7 alphabet characters', () => {
      const gsm7Chars = '@£$¥èéùìòÇ';
      const result = checkUnicode(gsm7Chars);
      expect(result).toBe(false);
    });

    it('should handle whitespace and newlines', () => {
      const result = updateCharCount('Line1\nLine2');
      expect(result.unicode).toBe(false);
    });

    it('should maintain char_list integrity for multipart messages', () => {
      const msg = 'A'.repeat(200);
      const result = updateCharCount(msg);
      expect(result.char_list.length).toBe(200);
    });

    it('should handle message with only special characters', () => {
      const result = updateCharCount('!@#$%^&*()');
      expect(result.unicode).toBe(false);
    });

    it('should calculate correct part boundaries for 7-bit', () => {
      const msg = 'A'.repeat(153);
      const result = updateCharCount(msg);
      expect(result.parts).toBe(1);
      expect(result.chars_sms).toBe(160);
    });

    it('should calculate correct part boundaries for Unicode', () => {
      const msg = '你'.repeat(67);
      const result = updateCharCount(msg);
      expect(result.parts).toBe(1);
      expect(result.chars_sms).toBe(70);
    });
  });
});