/**
 * URL Builder MCP Tests
 *
 * Test cases following the implementation plan specifications
 */

import { buildBookingUrl, buildInternalUrl, buildCompleteUrl, validateUrlParams } from '../urlBuilder';
import { UrlParams, UrlOptions } from '../types';

// Helper function to generate future dates for testing
function getFutureDates(daysFromNow = 1, stayDuration = 2) {
  const checkIn = new Date();
  checkIn.setDate(checkIn.getDate() + daysFromNow);
  const checkOut = new Date(checkIn);
  checkOut.setDate(checkOut.getDate() + stayDuration);

  return {
    checkIn: checkIn.toISOString().split('T')[0],
    checkOut: checkOut.toISOString().split('T')[0],
  };
}

// Set up environment variables for testing
process.env.BOOKING_URL_BASE = 'https://hotels.cloudbeds.com/en/reservas/lmKzDQ';
process.env.DEFAULT_CURRENCY = 'eur';

describe('URL Builder MCP', () => {
  describe('validateUrlParams', () => {
    it('should validate correct parameters', () => {
      const dates = getFutureDates();

      const params: UrlParams = {
        checkIn: dates.checkIn,
        checkOut: dates.checkOut,
      };

      const result = validateUrlParams(params);
      expect(result.valid).toBe(true);
      expect(result.errors).toEqual([]);
    });

    it('should reject missing required fields', () => {
      const params = {} as UrlParams;

      const result = validateUrlParams(params);
      expect(result.valid).toBe(false);
      expect(result.errors).toContain('checkIn y checkOut son requeridos');
    });

    it('should reject invalid date formats', () => {
      const params: UrlParams = {
        checkIn: '01/06/2024',
        checkOut: '2025-07-18',
      };

      const result = validateUrlParams(params);
      expect(result.valid).toBe(false);
      expect(result.errors).toContain('Formato de checkIn inválido. Use YYYY-MM-DD');
    });

    it('should reject checkout before checkin', () => {
      const params: UrlParams = {
        checkIn: '2025-07-18',
        checkOut: '2025-07-16',
      };

      const result = validateUrlParams(params);
      expect(result.valid).toBe(false);
      expect(result.errors).toContain('La fecha de salida debe ser posterior a la de entrada');
    });

    it('should reject invalid adults range', () => {
      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
        adults: 25,
      };

      const result = validateUrlParams(params);
      expect(result.valid).toBe(false);
      expect(result.errors).toContain('Número de adultos debe estar entre 1 y 20');
    });

    it('should reject invalid children range', () => {
      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
        children: 15,
      };

      const result = validateUrlParams(params);
      expect(result.valid).toBe(false);
      expect(result.errors).toContain('Número de niños debe estar entre 0 y 10');
    });
  });

  describe('buildBookingUrl', () => {
    it('should build basic localhost booking URL with required fields', () => {
      // Temporarily set localhost for this test
      const originalEnv = process.env.BASE_DOMAIN;
      process.env.BASE_DOMAIN = 'http://localhost:8080';

      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
        guestName: 'Juan Pérez',
        guestPhone: '+34612345678',
      };

      const url = buildBookingUrl(params, { addUtmTracking: false });
      expect(url).toBe(
        'http://localhost:8080/accommodation/reservations?checkIn=2025-07-16&checkOut=2025-07-18&adults=2&guestName=Juan+P%C3%A9rez&guestPhone=%2B34612345678'
      );

      // Restore original environment
      process.env.BASE_DOMAIN = originalEnv;
    });

    it('should build complete localhost booking URL with all parameters', () => {
      // Temporarily set localhost for this test
      const originalEnv = process.env.BOOKING_URL_BASE;
      process.env.BOOKING_URL_BASE = 'http://localhost:8080';

      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
        guestName: 'Juan Pérez',
        guestPhone: '+34612345678',
        guestEmail: 'juan@email.com',
        adults: 3,
        children: 1,
        roomType: 'garden-deluxe',
      };

      const url = buildBookingUrl(params);
      expect(url).toContain('adults=3');
      expect(url).toContain('children=1');
      expect(url).toContain('roomType=garden-deluxe');
      expect(url).toContain('guestName=Juan+P%C3%A9rez');
      expect(url).toContain('guestPhone=%2B34612345678');
      expect(url).toContain('guestEmail=juan%40email.com');
      expect(url).toContain('/accommodation/reservations?');

      // Restore original environment
      process.env.BOOKING_URL_BASE = originalEnv;
    });

    it('should not include children=0 in localhost URL', () => {
      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
        guestName: 'Juan Pérez',
        guestPhone: '+34612345678',
        children: 0,
      };

      const url = buildBookingUrl(params);
      expect(url).not.toContain('children=0');
    });

    it('should use query parameters format for localhost', () => {
      // Temporarily set localhost for this test
      const originalEnv = process.env.BOOKING_URL_BASE;
      process.env.BOOKING_URL_BASE = 'http://localhost:8080';

      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
        guestName: 'Juan Pérez',
        guestPhone: '+34612345678',
      };

      const url = buildBookingUrl(params);
      expect(url).toContain('?');
      expect(url).toMatch(/.*\?.*checkIn=.*&checkOut=.*/);
      expect(url).not.toContain('#');

      // Restore original environment
      process.env.BOOKING_URL_BASE = originalEnv;
    });

    it('should use hash fragment format for external URLs', () => {
      const originalEnv = process.env.BASE_DOMAIN;
      process.env.BASE_DOMAIN = 'https://hotels.cloudbeds.com/en/reservas/lmKzDQ';

      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
        guestName: 'Juan Pérez',
        guestPhone: '+34612345678',
      };

      const url = buildBookingUrl(params);
      expect(url).toContain('#');
      expect(url).toMatch(/.*#.*checkin=.*&checkout=.*/);
      expect(url).toContain('currency=eur');

      process.env.BASE_DOMAIN = originalEnv;
    });

    it('should throw error for missing required fields', () => {
      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
      };

      expect(() => buildBookingUrl(params)).toThrow('Parámetros inválidos');
    });

    it('should throw error for invalid date parameters', () => {
      const params: UrlParams = {
        checkIn: '2025-07-18',
        checkOut: '2025-07-16',
        guestName: 'Juan Pérez',
        guestPhone: '+34612345678',
      };

      expect(() => buildBookingUrl(params)).toThrow('Parámetros inválidos');
    });
  });

  describe('buildInternalUrl', () => {
    it('should build basic internal URL', () => {
      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
      };

      const url = buildInternalUrl(params, { addUtmTracking: false });
      expect(url).toBe('/accommodation/reservations?checkIn=2025-07-16&checkOut=2025-07-18');
    });

    it('should build complete internal URL with guest data', () => {
      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
        adults: 2,
        children: 1,
        guestName: 'Juan Pérez',
        guestEmail: 'juan@email.com',
        guestPhone: '+34123456789',
      };

      const url = buildInternalUrl(params);
      expect(url).toContain('adults=2');
      expect(url).toContain('children=1');
      expect(url).toContain('guestName=Juan+P%C3%A9rez');
      expect(url).toContain('guestEmail=juan%40email.com');
      expect(url).toContain('guestPhone=%2B34123456789');
    });

    it('should include roomType parameter in internal URL', () => {
      const params: UrlParams = {
        checkIn: '2025-07-21',
        checkOut: '2025-07-25',
        adults: 2,
        children: 1,
        roomType: 'garden-deluxe',
        guestName: 'María García López',
        guestEmail: 'maria.garcia@email.com',
        guestPhone: '+34665789123',
      };

      const url = buildInternalUrl(params);
      expect(url).toContain('roomType=garden-deluxe');
      expect(url).toContain('checkIn=2025-07-21');
      expect(url).toContain('checkOut=2025-07-25');
      expect(url).toContain('adults=2');
      expect(url).toContain('children=1');
      expect(url).toContain('guestName=Mar%C3%ADa+Garc%C3%ADa+L%C3%B3pez');
      expect(url).toContain('guestEmail=maria.garcia%40email.com');
      expect(url).toContain('guestPhone=%2B34665789123');
    });

    it('should use query parameters format', () => {
      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
      };

      const url = buildInternalUrl(params);
      expect(url).toContain('?');
      expect(url).toMatch(/.*\?.*checkIn=.*&checkOut=.*/);
    });

    it('should properly encode special characters', () => {
      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
        guestName: 'José María',
        guestEmail: 'jose@test.com',
      };

      const url = buildInternalUrl(params);
      expect(url).toContain('Jos%C3%A9+Mar%C3%ADa');
      expect(url).toContain('jose%40test.com');
    });

    it('should throw error for invalid parameters', () => {
      const params: UrlParams = {
        checkIn: '01/06/2024',
        checkOut: '2025-07-18',
      };

      expect(() => buildInternalUrl(params)).toThrow('Parámetros inválidos');
    });
  });

  describe('Environment Configuration', () => {
    it('should use environment variable for booking URL base', () => {
      const originalEnv = process.env.BASE_DOMAIN;
      process.env.BASE_DOMAIN = 'https://custom.booking.url/test';

      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
        guestName: 'Juan Pérez',
        guestPhone: '+34612345678',
      };

      const url = buildBookingUrl(params);
      expect(url).toContain('https://custom.booking.url/test');

      // Restore original environment
      process.env.BASE_DOMAIN = originalEnv;
    });

    it('should use default localhost URL when environment variable is not set', () => {
      const originalEnv = process.env.BASE_DOMAIN;
      const originalMcp = process.env.MCP_BASE_DOMAIN;
      const originalBooking = process.env.BOOKING_URL_BASE;
      delete process.env.BASE_DOMAIN;
      delete process.env.MCP_BASE_DOMAIN;
      delete process.env.BOOKING_URL_BASE;

      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
        guestName: 'Juan Pérez',
        guestPhone: '+34612345678',
      };

      const url = buildBookingUrl(params);
      expect(url).toContain('http://localhost:8080');
      expect(url).toContain('/accommodation/reservations?');

      // Restore original environment
      if (originalEnv) process.env.BASE_DOMAIN = originalEnv;
      if (originalMcp) process.env.MCP_BASE_DOMAIN = originalMcp;
      if (originalBooking) process.env.BOOKING_URL_BASE = originalBooking;
    });
  });

  describe('buildCompleteUrl', () => {
    beforeEach(() => {
      // Set up base domain for testing
      process.env.BASE_DOMAIN = 'https://example.com';
    });

    afterEach(() => {
      // Clean up environment
      delete process.env.BASE_DOMAIN;
      delete process.env.MCP_BASE_DOMAIN;
    });

    it('should build complete URL with base domain', () => {
      const url = buildCompleteUrl('/api/test', undefined, { addUtmTracking: false });
      expect(url).toBe('https://example.com/api/test');
    });

    it('should handle base domain with trailing slash', () => {
      process.env.BASE_DOMAIN = 'https://example.com/';
      const url = buildCompleteUrl('/api/test', undefined, { addUtmTracking: false });
      expect(url).toBe('https://example.com/api/test');
    });

    it('should handle relative path without leading slash', () => {
      const url = buildCompleteUrl('api/test', undefined, { addUtmTracking: false });
      expect(url).toBe('https://example.com/api/test');
    });

    it('should prefer BASE_DOMAIN over MCP_BASE_DOMAIN', () => {
      process.env.BASE_DOMAIN = 'https://primary.com';
      process.env.MCP_BASE_DOMAIN = 'https://secondary.com';
      const url = buildCompleteUrl('/api/test', undefined, { addUtmTracking: false });
      expect(url).toBe('https://primary.com/api/test');
    });

    it('should use MCP_BASE_DOMAIN when BASE_DOMAIN is not set', () => {
      delete process.env.BASE_DOMAIN;
      process.env.MCP_BASE_DOMAIN = 'https://secondary.com';
      const url = buildCompleteUrl('/api/test', undefined, { addUtmTracking: false });
      expect(url).toBe('https://secondary.com/api/test');
    });

    it('should use localhost fallback when no base domain is configured', () => {
      delete process.env.BASE_DOMAIN;
      delete process.env.MCP_BASE_DOMAIN;
      delete process.env.BOOKING_URL_BASE;
      const url = buildCompleteUrl('/api/test', undefined, { addUtmTracking: false });
      expect(url).toBe('http://localhost:8080/api/test');
    });

    it('should validate parameters when provided', () => {
      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
      };
      const url = buildCompleteUrl('/api/test', params, { addUtmTracking: false });
      expect(url).toBe('https://example.com/api/test?checkIn=2025-07-16&checkOut=2025-07-18');
    });

    it('should throw error for invalid parameters', () => {
      const params: UrlParams = {
        checkIn: '2025-07-18',
        checkOut: '2025-07-16',
      };
      expect(() => buildCompleteUrl('/api/test', params)).toThrow('Parámetros inválidos');
    });
  });

  describe('buildInternalUrl with options', () => {
    beforeEach(() => {
      process.env.BASE_DOMAIN = 'https://example.com';
    });

    afterEach(() => {
      delete process.env.BASE_DOMAIN;
    });

    it('should return relative URL by default', () => {
      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
      };
      const url = buildInternalUrl(params, { addUtmTracking: false });
      expect(url).toBe('/accommodation/reservations?checkIn=2025-07-16&checkOut=2025-07-18');
    });

    it('should return complete URL when useBaseDomain is true', () => {
      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
      };
      const url = buildInternalUrl(params, { useBaseDomain: true, addUtmTracking: false });
      expect(url).toBe('https://example.com/accommodation/reservations?checkIn=2025-07-16&checkOut=2025-07-18');
    });

    it('should build URL with base domain when useBaseDomain is true', () => {
      process.env.BASE_DOMAIN = 'https://example.com';
      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
      };
      const url = buildInternalUrl(params, { useBaseDomain: true, addUtmTracking: false });
      expect(url).toBe('https://example.com/accommodation/reservations?checkIn=2025-07-16&checkOut=2025-07-18');
    });

    it('should use localhost fallback when useBaseDomain is true but BASE_DOMAIN not configured', () => {
      delete process.env.BASE_DOMAIN;
      delete process.env.MCP_BASE_DOMAIN;
      delete process.env.BOOKING_URL_BASE;
      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
      };
      const url = buildInternalUrl(params, { useBaseDomain: true, addUtmTracking: false });
      expect(url).toBe('http://localhost:8080/accommodation/reservations?checkIn=2025-07-16&checkOut=2025-07-18');
    });
  });

  describe('buildCompleteUrl', () => {
    beforeEach(() => {
      process.env.BASE_DOMAIN = 'https://example.com';
    });

    afterEach(() => {
      delete process.env.BASE_DOMAIN;
      delete process.env.MCP_BASE_DOMAIN;
    });

    it('should build complete URL with relative path', () => {
      const url = buildCompleteUrl('/api/bookings', undefined, { addUtmTracking: false });
      expect(url).toBe('https://example.com/api/bookings');
    });

    it('should build complete URL with relative path and parameters', () => {
      const params: UrlParams = {
        checkIn: '2025-07-16',
        checkOut: '2025-07-18',
        adults: 2,
      };
      const url = buildCompleteUrl('/api/bookings', params, { addUtmTracking: false });
      expect(url).toBe('https://example.com/api/bookings?checkIn=2025-07-16&checkOut=2025-07-18&adults=2');
    });

    it('should add leading slash if missing', () => {
      const url = buildCompleteUrl('api/bookings', undefined, { addUtmTracking: false });
      expect(url).toBe('https://example.com/api/bookings');
    });

    it('should use localhost fallback when BASE_DOMAIN not configured', () => {
      delete process.env.BASE_DOMAIN;
      delete process.env.MCP_BASE_DOMAIN;
      delete process.env.BOOKING_URL_BASE;
      const url = buildCompleteUrl('/api/bookings', undefined, { addUtmTracking: false });
      expect(url).toBe('http://localhost:8080/api/bookings');
    });

    it('should validate parameters when provided', () => {
      const params: UrlParams = {
        checkIn: 'invalid-date',
        checkOut: '2025-07-18',
      };
      expect(() => {
        buildCompleteUrl('/api/bookings', params);
      }).toThrow('Parámetros inválidos');
    });
  });

  describe('UTM Tracking', () => {
    beforeEach(() => {
      process.env.BASE_DOMAIN = 'https://hotels.cloudbeds.com/en/reservas/lmKzDQ';
    });

    afterEach(() => {
      delete process.env.BASE_DOMAIN;
    });

    it('should add default UTM parameters to booking URL', () => {
      const dates = getFutureDates();
      const params: UrlParams = {
        checkIn: dates.checkIn,
        checkOut: dates.checkOut,
        guestName: 'Juan Pérez',
        guestPhone: '+34612345678',
      };

      const url = buildBookingUrl(params);
      expect(url).toContain('utm_source=claude-desktop');
      expect(url).toContain('utm_medium=ai-assistant');
      expect(url).toContain('utm_campaign=url-builder-mcp');
      expect(url).toContain('utm_content=mcp-generated-link');
    });

    it('should allow custom UTM parameters', () => {
      const dates = getFutureDates();
      const params: UrlParams = {
        checkIn: dates.checkIn,
        checkOut: dates.checkOut,
        guestName: 'Juan Pérez',
        guestPhone: '+34612345678',
      };

      const options: UrlOptions = {
        customUtm: {
          utm_campaign: 'custom-campaign',
          utm_source: 'custom-source',
        },
      };

      const url = buildBookingUrl(params, options);
      expect(url).toContain('utm_source=custom-source');
      expect(url).toContain('utm_campaign=custom-campaign');
      expect(url).toContain('utm_medium=ai-assistant'); // Default should remain
    });

    it('should allow disabling UTM tracking', () => {
      const dates = getFutureDates();
      const params: UrlParams = {
        checkIn: dates.checkIn,
        checkOut: dates.checkOut,
        guestName: 'Juan Pérez',
        guestPhone: '+34612345678',
      };

      const options: UrlOptions = {
        addUtmTracking: false,
      };

      const url = buildBookingUrl(params, options);
      expect(url).not.toContain('utm_');
    });

    it('should add UTM parameters to internal URLs', () => {
      const dates = getFutureDates();
      const params: UrlParams = {
        checkIn: dates.checkIn,
        checkOut: dates.checkOut,
      };

      const url = buildInternalUrl(params);
      expect(url).toContain('utm_source=claude-desktop');
      expect(url).toContain('utm_medium=ai-assistant');
      expect(url).toContain('utm_campaign=url-builder-mcp');
    });

    it('should add UTM parameters to complete URLs', () => {
      const dates = getFutureDates();
      const params: UrlParams = {
        checkIn: dates.checkIn,
        checkOut: dates.checkOut,
      };

      const url = buildCompleteUrl('/api/bookings', params);
      expect(url).toContain('utm_source=claude-desktop');
      expect(url).toContain('utm_medium=ai-assistant');
      expect(url).toContain('utm_campaign=url-builder-mcp');
    });
  });
});
