import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { getTenantFromSubdomain } from '../api';

describe('getTenantFromSubdomain', () => {
  // Store original location to restore after tests
  const originalLocation = window.location;

  // Helper function to mock window.location.hostname
  const mockLocation = (hostname: string) => {
    Object.defineProperty(window, 'location', {
      value: {
        ...originalLocation,
        hostname,
      },
      writable: true,
      configurable: true,
    });
  };

  afterEach(() => {
    // Restore original location after each test
    Object.defineProperty(window, 'location', {
      value: originalLocation,
      writable: true,
      configurable: true,
    });
  });

  describe('localhost and IP addresses', () => {
    it('returns "public" for localhost', () => {
      mockLocation('localhost');
      expect(getTenantFromSubdomain()).toBe('public');
    });

    it('returns "public" for 127.0.0.1', () => {
      mockLocation('127.0.0.1');
      expect(getTenantFromSubdomain()).toBe('public');
    });

    it('returns first octet for 0.0.0.0 (treated as subdomain)', () => {
      mockLocation('0.0.0.0');
      // 0.0.0.0 splits into 4 parts, so parts.length > 2
      // Returns the first part '0' (treated like a subdomain)
      const result = getTenantFromSubdomain();
      expect(result).toBe('0');
    });
  });

  describe('base domains without subdomains', () => {
    it('returns "public" for "example.com" (no subdomain)', () => {
      mockLocation('example.com');
      expect(getTenantFromSubdomain()).toBe('public');
    });

    it('returns "public" for "chronoflow.com" (no subdomain)', () => {
      mockLocation('chronoflow.com');
      expect(getTenantFromSubdomain()).toBe('public');
    });

    it('returns "public" for "smoothschedule.com" (no subdomain)', () => {
      mockLocation('smoothschedule.com');
      expect(getTenantFromSubdomain()).toBe('public');
    });

    it('returns "public" for single-part hostname', () => {
      mockLocation('localhost');
      expect(getTenantFromSubdomain()).toBe('public');
    });
  });

  describe('single-level subdomains', () => {
    it('returns subdomain for "tenant.example.com"', () => {
      mockLocation('tenant.example.com');
      expect(getTenantFromSubdomain()).toBe('tenant');
    });

    it('returns subdomain for "plumbing.chronoflow.com"', () => {
      mockLocation('plumbing.chronoflow.com');
      expect(getTenantFromSubdomain()).toBe('plumbing');
    });

    it('returns subdomain for "demo.lvh.me"', () => {
      mockLocation('demo.lvh.me');
      expect(getTenantFromSubdomain()).toBe('demo');
    });

    it('returns subdomain for "platform.lvh.me"', () => {
      mockLocation('platform.lvh.me');
      expect(getTenantFromSubdomain()).toBe('platform');
    });

    it('returns subdomain for "business1.smoothschedule.com"', () => {
      mockLocation('business1.smoothschedule.com');
      expect(getTenantFromSubdomain()).toBe('business1');
    });
  });

  describe('deep subdomains (multiple levels)', () => {
    it('returns first subdomain for "tenant.sub.example.com"', () => {
      mockLocation('tenant.sub.example.com');
      expect(getTenantFromSubdomain()).toBe('tenant');
    });

    it('returns first subdomain for "app.tenant.example.com"', () => {
      mockLocation('app.tenant.example.com');
      expect(getTenantFromSubdomain()).toBe('app');
    });

    it('returns first subdomain for "api.staging.chronoflow.com"', () => {
      mockLocation('api.staging.chronoflow.com');
      expect(getTenantFromSubdomain()).toBe('api');
    });

    it('returns first subdomain for "a.b.c.d.e.com"', () => {
      mockLocation('a.b.c.d.e.com');
      expect(getTenantFromSubdomain()).toBe('a');
    });

    it('returns first subdomain for "platform.demo.lvh.me"', () => {
      mockLocation('platform.demo.lvh.me');
      expect(getTenantFromSubdomain()).toBe('platform');
    });
  });

  describe('special characters and edge cases', () => {
    it('handles subdomain with hyphens', () => {
      mockLocation('my-business.example.com');
      expect(getTenantFromSubdomain()).toBe('my-business');
    });

    it('handles subdomain with numbers', () => {
      mockLocation('business123.example.com');
      expect(getTenantFromSubdomain()).toBe('business123');
    });

    it('handles subdomain starting with number', () => {
      mockLocation('123business.example.com');
      expect(getTenantFromSubdomain()).toBe('123business');
    });

    it('handles subdomain with mixed case (returns as-is)', () => {
      mockLocation('MyBusiness.example.com');
      // The function returns the first part as-is without normalization
      expect(getTenantFromSubdomain()).toBe('MyBusiness');
    });

    it('handles very long subdomain', () => {
      const longSubdomain = 'a'.repeat(63); // Max subdomain length per DNS spec
      mockLocation(`${longSubdomain}.example.com`);
      expect(getTenantFromSubdomain()).toBe(longSubdomain);
    });
  });

  describe('localhost variations with ports', () => {
    it('handles localhost with port (returns based on hostname only)', () => {
      // Note: window.location.hostname excludes the port
      mockLocation('localhost');
      expect(getTenantFromSubdomain()).toBe('public');
    });

    it('handles subdomain.lvh.me with port (returns based on hostname only)', () => {
      // window.location.hostname returns just the hostname without port
      mockLocation('demo.lvh.me');
      expect(getTenantFromSubdomain()).toBe('demo');
    });
  });

  describe('consistency and idempotency', () => {
    it('returns same result when called multiple times', () => {
      mockLocation('tenant.example.com');
      const firstCall = getTenantFromSubdomain();
      const secondCall = getTenantFromSubdomain();
      const thirdCall = getTenantFromSubdomain();

      expect(firstCall).toBe('tenant');
      expect(secondCall).toBe('tenant');
      expect(thirdCall).toBe('tenant');
      expect(firstCall).toBe(secondCall);
      expect(secondCall).toBe(thirdCall);
    });

    it('returns updated result when hostname changes', () => {
      mockLocation('tenant1.example.com');
      expect(getTenantFromSubdomain()).toBe('tenant1');

      mockLocation('tenant2.example.com');
      expect(getTenantFromSubdomain()).toBe('tenant2');

      mockLocation('localhost');
      expect(getTenantFromSubdomain()).toBe('public');
    });
  });

  describe('real-world scenarios', () => {
    it('handles development environment (lvh.me)', () => {
      mockLocation('demo.lvh.me');
      expect(getTenantFromSubdomain()).toBe('demo');
    });

    it('handles platform subdomain', () => {
      mockLocation('platform.smoothschedule.com');
      expect(getTenantFromSubdomain()).toBe('platform');
    });

    it('handles business tenant subdomain', () => {
      mockLocation('acme-plumbing.smoothschedule.com');
      expect(getTenantFromSubdomain()).toBe('acme-plumbing');
    });

    it('handles local development on localhost', () => {
      mockLocation('localhost');
      expect(getTenantFromSubdomain()).toBe('public');
    });

    it('handles production base domain', () => {
      mockLocation('smoothschedule.com');
      expect(getTenantFromSubdomain()).toBe('public');
    });
  });

  describe('TLD variations', () => {
    it('handles .io domain', () => {
      mockLocation('tenant.example.io');
      expect(getTenantFromSubdomain()).toBe('tenant');
    });

    it('handles .co.uk domain (treated as 3 parts, returns first)', () => {
      mockLocation('tenant.example.co.uk');
      // Since parts.length > 2, it returns first part
      expect(getTenantFromSubdomain()).toBe('tenant');
    });

    it('handles .app domain', () => {
      mockLocation('business.example.app');
      expect(getTenantFromSubdomain()).toBe('business');
    });

    it('handles base .co.uk domain (no subdomain)', () => {
      mockLocation('example.co.uk');
      // parts = ['example', 'co', 'uk'], length is 3 > 2
      // So it returns 'example' (the first part)
      expect(getTenantFromSubdomain()).toBe('example');
    });
  });

  describe('empty and whitespace', () => {
    it('handles empty string hostname gracefully', () => {
      mockLocation('');
      // Empty string split by '.' returns ['']
      // parts.length = 1, which is not > 2
      expect(getTenantFromSubdomain()).toBe('public');
    });

    it('handles hostname with only dots', () => {
      mockLocation('...');
      // '...'.split('.') returns ['', '', '', '']
      // parts.length = 4 > 2, returns first part (empty string)
      expect(getTenantFromSubdomain()).toBe('');
    });
  });
});
