/**
 * Tests for URL Utilities
 * FE-TEST-004: Test all URL utility functions
 */

import { describe, it, expect } from 'vitest';
import {
  buildUrl,
  parseQueryString,
  buildQueryString,
  getUrlPathname,
  getUrlHostname,
  isAbsoluteUrl,
  isRelativeUrl,
  normalizeUrl,
  addQueryParam,
  removeQueryParam,
  getQueryParam,
  hasQueryParam,
  extractDomain,
  extractProtocol,
  extractPort,
  isValidUrl,
  isSecureUrl,
  getUrlWithoutQuery,
  getUrlWithoutHash,
  getHashFromUrl,
  setHashInUrl,
  removeHashFromUrl,
  getBaseUrl,
  getRelativePath,
  isSameOrigin,
  getUrlSegments,
  getLastUrlSegment,
  getParentUrl,
} from './url';

describe('url utilities', () => {
  describe('buildUrl', () => {
    it('should build URL with base and path', () => {
      const result = buildUrl('https://example.com', '/api/users');
      expect(result).toBe('https://example.com/api/users');
    });

    it('should add query parameters', () => {
      const result = buildUrl('https://example.com', '/api/users', {
        page: 1,
        limit: 10,
      });
      expect(result).toContain('page=1');
      expect(result).toContain('limit=10');
    });

    it('should ignore null and undefined params', () => {
      const result = buildUrl('https://example.com', '/api/users', {
        page: 1,
        limit: null,
      });
      expect(result).toContain('page=1');
      expect(result).not.toContain('limit');
    });
  });

  describe('parseQueryString', () => {
    it('should parse query string', () => {
      const result = parseQueryString('?page=1&limit=10');
      expect(result.page).toBe('1');
      expect(result.limit).toBe('10');
    });

    it('should return empty object for empty string', () => {
      const result = parseQueryString('');
      expect(result).toEqual({});
    });
  });

  describe('buildQueryString', () => {
    it('should build query string from params', () => {
      const result = buildQueryString({ page: 1, limit: 10 });
      expect(result).toContain('page=1');
      expect(result).toContain('limit=10');
    });

    it('should ignore null and undefined', () => {
      const result = buildQueryString({ page: 1, limit: null });
      expect(result).toContain('page=1');
      expect(result).not.toContain('limit');
    });
  });

  describe('getUrlPathname', () => {
    it('should extract pathname', () => {
      expect(getUrlPathname('https://example.com/api/users')).toBe(
        '/api/users',
      );
    });

    it('should return original string if invalid URL', () => {
      expect(getUrlPathname('invalid-url')).toBe('invalid-url');
    });
  });

  describe('getUrlHostname', () => {
    it('should extract hostname', () => {
      expect(getUrlHostname('https://example.com/api/users')).toBe(
        'example.com',
      );
    });

    it('should return empty string for invalid URL', () => {
      expect(getUrlHostname('invalid-url')).toBe('');
    });
  });

  describe('isAbsoluteUrl', () => {
    it('should return true for absolute URLs', () => {
      expect(isAbsoluteUrl('https://example.com')).toBe(true);
      expect(isAbsoluteUrl('http://example.com')).toBe(true);
    });

    it('should return false for relative URLs', () => {
      expect(isAbsoluteUrl('/api/users')).toBe(false);
    });

    it('should return false for invalid URLs', () => {
      expect(isAbsoluteUrl('not-a-url')).toBe(false);
    });
  });

  describe('isRelativeUrl', () => {
    it('should return true for relative URLs', () => {
      expect(isRelativeUrl('/api/users')).toBe(true);
    });

    it('should return false for absolute URLs', () => {
      expect(isRelativeUrl('https://example.com')).toBe(false);
    });
  });

  describe('normalizeUrl', () => {
    it('should normalize valid URL', () => {
      const result = normalizeUrl('https://example.com/api');
      expect(result).toBe('https://example.com/api');
    });

    it('should return original string if invalid', () => {
      expect(normalizeUrl('invalid-url')).toBe('invalid-url');
    });
  });

  describe('addQueryParam', () => {
    it('should add query parameter', () => {
      const result = addQueryParam('https://example.com', 'page', '1');
      expect(result).toContain('page=1');
    });

    it('should return original URL if invalid', () => {
      expect(addQueryParam('invalid-url', 'page', '1')).toBe('invalid-url');
    });
  });

  describe('removeQueryParam', () => {
    it('should remove query parameter', () => {
      const result = removeQueryParam(
        'https://example.com?page=1&limit=10',
        'page',
      );
      expect(result).not.toContain('page=1');
      expect(result).toContain('limit=10');
    });
  });

  describe('getQueryParam', () => {
    it('should get query parameter', () => {
      const result = getQueryParam('https://example.com?page=1', 'page');
      expect(result).toBe('1');
    });

    it('should return null if param not found', () => {
      const result = getQueryParam('https://example.com?page=1', 'limit');
      expect(result).toBeNull();
    });
  });

  describe('hasQueryParam', () => {
    it('should return true if param exists', () => {
      expect(hasQueryParam('https://example.com?page=1', 'page')).toBe(true);
    });

    it('should return false if param does not exist', () => {
      expect(hasQueryParam('https://example.com?page=1', 'limit')).toBe(false);
    });
  });

  describe('extractDomain', () => {
    it('should extract domain', () => {
      expect(extractDomain('https://example.com/api')).toBe('example.com');
    });

    it('should return empty string for invalid URL', () => {
      expect(extractDomain('invalid-url')).toBe('');
    });
  });

  describe('extractProtocol', () => {
    it('should extract protocol', () => {
      expect(extractProtocol('https://example.com')).toBe('https:');
    });
  });

  describe('extractPort', () => {
    it('should extract port', () => {
      expect(extractPort('https://example.com:8080')).toBe('8080');
    });
  });

  describe('isValidUrl', () => {
    it('should return true for valid URLs', () => {
      expect(isValidUrl('https://example.com')).toBe(true);
      expect(isValidUrl('http://example.com')).toBe(true);
    });

    it('should return false for invalid URLs', () => {
      expect(isValidUrl('not-a-url')).toBe(false);
    });
  });

  describe('isSecureUrl', () => {
    it('should return true for HTTPS', () => {
      expect(isSecureUrl('https://example.com')).toBe(true);
    });

    it('should return false for HTTP', () => {
      expect(isSecureUrl('http://example.com')).toBe(false);
    });
  });

  describe('getUrlWithoutQuery', () => {
    it('should remove query string', () => {
      expect(getUrlWithoutQuery('https://example.com?page=1')).toBe(
        'https://example.com/',
      );
    });
  });

  describe('getUrlWithoutHash', () => {
    it('should remove hash', () => {
      expect(getUrlWithoutHash('https://example.com#section')).toBe(
        'https://example.com/',
      );
    });
  });

  describe('getHashFromUrl', () => {
    it('should extract hash', () => {
      expect(getHashFromUrl('https://example.com#section')).toBe('#section');
    });
  });

  describe('setHashInUrl', () => {
    it('should set hash', () => {
      const result = setHashInUrl('https://example.com', 'section');
      expect(result).toContain('#section');
    });
  });

  describe('removeHashFromUrl', () => {
    it('should remove hash', () => {
      const result = removeHashFromUrl('https://example.com#section');
      expect(result).not.toContain('#section');
    });
  });

  describe('getBaseUrl', () => {
    it('should get base URL', () => {
      expect(getBaseUrl('https://example.com/api/users')).toBe(
        'https://example.com',
      );
    });
  });

  describe('getRelativePath', () => {
    it('should get relative path', () => {
      expect(getRelativePath('https://example.com/api/users')).toBe(
        '/api/users',
      );
    });
  });

  describe('isSameOrigin', () => {
    it('should return true for same origin', () => {
      expect(
        isSameOrigin('https://example.com/api', 'https://example.com/users'),
      ).toBe(true);
    });

    it('should return false for different origins', () => {
      expect(isSameOrigin('https://example.com', 'https://other.com')).toBe(
        false,
      );
    });
  });

  describe('getUrlSegments', () => {
    it('should get URL segments', () => {
      expect(getUrlSegments('https://example.com/api/users/123')).toEqual([
        'api',
        'users',
        '123',
      ]);
    });
  });

  describe('getLastUrlSegment', () => {
    it('should get last segment', () => {
      expect(getLastUrlSegment('https://example.com/api/users/123')).toBe(
        '123',
      );
    });
  });

  describe('getParentUrl', () => {
    it('should get parent URL', () => {
      const result = getParentUrl('https://example.com/api/users/123');
      expect(result).toContain('/api/users');
      expect(result).not.toContain('/123');
    });
  });
});
