import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { ScriptBlocker } from './ScriptBlocker';
import type { ConsentConfig } from '../types';

describe('ScriptBlocker', () => {
  let blocker: ScriptBlocker;
  const mockConfig: ConsentConfig = {
    apiEndpoint: 'https://api.example.com',
    siteId: 'test-site',
    debug: false,
  };

  beforeEach(() => {
    // Clear document body
    document.body.innerHTML = '';
    blocker = new ScriptBlocker(mockConfig);
  });

  afterEach(() => {
    blocker.destroy();
  });

  describe('constructor', () => {
    it('should create blocker with essential category enabled by default', () => {
      expect(blocker.isCategoryEnabled('essential')).toBe(true);
    });

    it('should have other categories disabled by default', () => {
      expect(blocker.isCategoryEnabled('analytics')).toBe(false);
      expect(blocker.isCategoryEnabled('marketing')).toBe(false);
      expect(blocker.isCategoryEnabled('functional')).toBe(false);
      expect(blocker.isCategoryEnabled('social')).toBe(false);
    });
  });

  describe('init', () => {
    it('should process existing scripts with data-consent', () => {
      // Add a blocked script before init
      const script = document.createElement('script');
      script.setAttribute('data-consent', 'analytics');
      script.setAttribute('data-src', 'https://analytics.example.com/script.js');
      script.type = 'text/plain';
      document.body.appendChild(script);

      blocker.init();

      // Script should remain blocked (analytics not enabled)
      expect(script.type).toBe('text/plain');
    });

    it('should start MutationObserver for new elements', () => {
      blocker.init();

      // Add a script after init
      const script = document.createElement('script');
      script.setAttribute('data-consent', 'analytics');
      script.setAttribute('data-src', 'https://analytics.example.com/script.js');
      script.type = 'text/plain';
      document.body.appendChild(script);

      // Script should be tracked (processed)
      expect(script.type).toBe('text/plain');
    });
  });

  describe('enableCategory', () => {
    it('should enable a category', () => {
      blocker.enableCategory('analytics');

      expect(blocker.isCategoryEnabled('analytics')).toBe(true);
    });

    it('should not duplicate enabling', () => {
      blocker.enableCategory('analytics');
      blocker.enableCategory('analytics');

      expect(blocker.isCategoryEnabled('analytics')).toBe(true);
    });

    it('should activate blocked scripts for the category', () => {
      const script = document.createElement('script');
      script.setAttribute('data-consent', 'analytics');
      script.setAttribute('data-src', 'https://analytics.example.com/script.js');
      script.type = 'text/plain';
      document.body.appendChild(script);

      blocker.init();
      blocker.enableCategory('analytics');

      // The original script should be replaced
      const scripts = document.querySelectorAll('script[src="https://analytics.example.com/script.js"]');
      expect(scripts.length).toBe(1);
    });
  });

  describe('disableCategory', () => {
    it('should disable a category', () => {
      blocker.enableCategory('analytics');
      blocker.disableCategory('analytics');

      expect(blocker.isCategoryEnabled('analytics')).toBe(false);
    });

    it('should not disable essential category', () => {
      blocker.disableCategory('essential');

      expect(blocker.isCategoryEnabled('essential')).toBe(true);
    });
  });

  describe('blockAll', () => {
    it('should block all categories except essential', () => {
      blocker.enableCategory('analytics');
      blocker.enableCategory('marketing');
      blocker.enableCategory('social');

      blocker.blockAll();

      expect(blocker.isCategoryEnabled('essential')).toBe(true);
      expect(blocker.isCategoryEnabled('analytics')).toBe(false);
      expect(blocker.isCategoryEnabled('marketing')).toBe(false);
      expect(blocker.isCategoryEnabled('social')).toBe(false);
    });
  });

  describe('isCategoryEnabled', () => {
    it('should return true for enabled categories', () => {
      blocker.enableCategory('functional');
      expect(blocker.isCategoryEnabled('functional')).toBe(true);
    });

    it('should return false for disabled categories', () => {
      expect(blocker.isCategoryEnabled('marketing')).toBe(false);
    });
  });

  describe('destroy', () => {
    it('should disconnect the MutationObserver', () => {
      blocker.init();
      blocker.destroy();

      // After destroy, adding new elements should not trigger processing
      // This is hard to test directly, but we can verify it doesn't throw
      expect(() => {
        const script = document.createElement('script');
        script.setAttribute('data-consent', 'analytics');
        document.body.appendChild(script);
      }).not.toThrow();
    });
  });

  describe('script processing', () => {
    it('should handle external scripts with data-src', () => {
      const script = document.createElement('script');
      script.setAttribute('data-consent', 'essential');
      script.setAttribute('data-src', 'https://essential.example.com/script.js');
      script.type = 'text/plain';
      document.body.appendChild(script);

      blocker.init();

      // Essential is enabled, so script should be activated
      const activatedScript = document.querySelector('script[src="https://essential.example.com/script.js"]');
      expect(activatedScript).toBeDefined();
    });

    it('should handle inline scripts', () => {
      const script = document.createElement('script');
      script.setAttribute('data-consent', 'essential');
      script.type = 'text/plain';
      script.textContent = 'console.log("test");';
      document.body.appendChild(script);

      blocker.init();

      // Check that script was processed
      const scripts = document.querySelectorAll('script');
      expect(scripts.length).toBeGreaterThan(0);
    });
  });

  describe('iframe processing', () => {
    it('should block iframes with data-consent', () => {
      const iframe = document.createElement('iframe');
      iframe.setAttribute('data-consent', 'social');
      iframe.setAttribute('data-src', 'https://social.example.com/embed');
      document.body.appendChild(iframe);

      blocker.init();

      // Should be hidden and have placeholder
      expect(iframe.style.display).toBe('none');
    });

    it('should show placeholder for blocked iframes', () => {
      const iframe = document.createElement('iframe');
      iframe.setAttribute('data-consent', 'social');
      iframe.setAttribute('data-src', 'https://social.example.com/embed');
      document.body.appendChild(iframe);

      blocker.init();

      const placeholder = document.querySelector('.bp-consent-placeholder');
      expect(placeholder).toBeDefined();
    });

    it('should activate iframe when category enabled', () => {
      const iframe = document.createElement('iframe');
      iframe.setAttribute('data-consent', 'social');
      iframe.setAttribute('data-src', 'https://social.example.com/embed');
      document.body.appendChild(iframe);

      blocker.init();
      blocker.enableCategory('social');

      expect(iframe.src).toBe('https://social.example.com/embed');
      expect(iframe.style.display).toBe('');
    });

    it('should remove placeholder when iframe activated', () => {
      const iframe = document.createElement('iframe');
      iframe.setAttribute('data-consent', 'social');
      iframe.setAttribute('data-src', 'https://social.example.com/embed');
      document.body.appendChild(iframe);

      blocker.init();
      blocker.enableCategory('social');

      const placeholder = document.querySelector('.bp-consent-placeholder');
      expect(placeholder).toBeNull();
    });
  });

  describe('placeholder button', () => {
    it('should dispatch event when placeholder button clicked', () => {
      const iframe = document.createElement('iframe');
      iframe.setAttribute('data-consent', 'marketing');
      iframe.setAttribute('data-src', 'https://marketing.example.com/embed');
      document.body.appendChild(iframe);

      blocker.init();

      const eventHandler = vi.fn();
      window.addEventListener('bp-consent-request', eventHandler);

      const button = document.querySelector('.bp-consent-placeholder-btn') as HTMLButtonElement;
      button?.click();

      expect(eventHandler).toHaveBeenCalled();
      expect(eventHandler.mock.calls[0][0].detail.category).toBe('marketing');

      window.removeEventListener('bp-consent-request', eventHandler);
    });
  });

  describe('category names', () => {
    it('should show correct category name in placeholder', () => {
      const iframe = document.createElement('iframe');
      iframe.setAttribute('data-consent', 'analytics');
      iframe.setAttribute('data-src', 'https://analytics.example.com/embed');
      document.body.appendChild(iframe);

      blocker.init();

      const placeholder = document.querySelector('.bp-consent-placeholder');
      expect(placeholder?.innerHTML).toContain('Statistik-Cookies aktivieren');
    });
  });

  describe('debug mode', () => {
    it('should log when debug is enabled', () => {
      const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});

      const debugBlocker = new ScriptBlocker({
        ...mockConfig,
        debug: true,
      });

      debugBlocker.init();
      debugBlocker.enableCategory('analytics');

      expect(consoleSpy).toHaveBeenCalled();
      consoleSpy.mockRestore();
      debugBlocker.destroy();
    });
  });

  describe('nested elements', () => {
    it('should process scripts in nested containers', () => {
      const container = document.createElement('div');
      const script = document.createElement('script');
      script.setAttribute('data-consent', 'essential');
      script.setAttribute('data-src', 'https://essential.example.com/nested.js');
      script.type = 'text/plain';
      container.appendChild(script);

      blocker.init();
      document.body.appendChild(container);

      // Give MutationObserver time to process
      const activatedScript = document.querySelector('script[src="https://essential.example.com/nested.js"]');
      expect(activatedScript).toBeDefined();
    });
  });
});
