import {
  getNumberFromPathQuery,
  getStringFromPathQuery,
  handleValueInSearchParams,
  saveValuesToPathQuery,
  writeLocation,
} from './location.helper';

vi.mock('vue-router', () => ({
  useRoute: vi.fn(),
}));

describe('search and filter composable', () => {
  let previous: any;
  beforeEach(() => {
    vi.resetAllMocks();
    previous = global.window.location;
    //@ts-ignore
    delete global.window.location;
  });
  afterEach(() => {
    global.window.location = previous;
  });

  describe('writeLocation', () => {
    test('should change current url with correct query parameters', async () => {
      global.window.location = {
        ...previous,
        protocol: 'https:',
        host: 'localhost/',
        pathname: 'path',
        search: '?query=toto',
      };

      const replaceStateSpy = vi
        .spyOn(global.window.history, 'replaceState')
        .mockImplementation(() => {});

      const expectedUrl = 'https://localhost/path?param=value';
      const searchParams = new URLSearchParams('');
      searchParams.set('param', 'value');
      writeLocation(searchParams);
      expect(replaceStateSpy).toBeCalledWith(
        { path: expectedUrl },
        '',
        expectedUrl,
      );
    });
  });

  describe('handleValueInSearchParams', () => {
    test('should delete existing searchParam if no longer exists', () => {
      const searchParams = new URLSearchParams('param=value&second=toto');
      const result = handleValueInSearchParams(searchParams, 'param', '');
      expect(result.toString()).toEqual('second=toto');
    });
    test('should not add searchParam if no value', () => {
      const searchParams = new URLSearchParams('param=value&second=toto');
      const result = handleValueInSearchParams(searchParams, 'third', '');
      expect(result.toString()).toEqual('param=value&second=toto');
    });
    test('should modify searchParam if value', () => {
      const searchParams = new URLSearchParams('param=value&second=toto');
      const result = handleValueInSearchParams(searchParams, 'second', 'titi');
      expect(result.toString()).toEqual('param=value&second=titi');
    });
    test('should add searchParam if value not present', () => {
      const searchParams = new URLSearchParams('param=value&second=toto');
      const result = handleValueInSearchParams(searchParams, 'third', 'titi');
      expect(result.toString()).toEqual('param=value&second=toto&third=titi');
    });
  });

  describe('getNumberFromPathQuery', () => {
    it('should return null if no entry in url', () => {
      global.window.location = {
        ...previous,
        protocol: 'https:',
        host: 'localhost/',
        pathname: 'path',
        search: '',
      };
      expect(getNumberFromPathQuery('table-size')).toEqual(null);
    });
    it('should return null if entry is not a number in url', () => {
      global.window.location = {
        ...previous,
        protocol: 'https:',
        host: 'localhost/',
        pathname: 'path',
        search: '?table-size=toto',
      };
      expect(getNumberFromPathQuery('table-size')).toEqual(null);
    });
    it('should return value if entry is a number in url', () => {
      global.window.location = {
        ...previous,
        protocol: 'https:',
        host: 'localhost/',
        pathname: 'path',
        search: '?table-size=5',
      };
      expect(getNumberFromPathQuery('table-size')).toEqual(5);
    });
  });

  describe('getStringFromPathQuery', () => {
    it('should return null if no entry in url', () => {
      global.window.location = {
        ...previous,
        protocol: 'https:',
        host: 'localhost/',
        pathname: 'path',
        search: '',
      };
      expect(getStringFromPathQuery('table-size')).toEqual(null);
    });
    it('should return value if entry is a number in url', () => {
      global.window.location = {
        ...previous,
        protocol: 'https:',
        host: 'localhost/',
        pathname: 'path',
        search: '?table-size=5',
      };
      expect(getStringFromPathQuery('table-size')).toEqual('5');
    });
  });

  describe('saveValuesToPathQuery', () => {
    it('should write value in query and push history', () => {
      global.window.location = {
        ...previous,
        protocol: 'https:',
        host: 'localhost/',
        pathname: 'path',
        search: '?query=toto',
      };

      const replaceStateSpy = vi
        .spyOn(global.window.history, 'replaceState')
        .mockImplementation(() => {});

      saveValuesToPathQuery([{ key: 'key', value: 'value' }]);
      expect(replaceStateSpy).toHaveBeenCalledWith(
        { path: 'https://localhost/path?query=toto&key=value' },
        '',
        'https://localhost/path?query=toto&key=value',
      );
    });
    it('should replace value in query and push history', () => {
      global.window.location = {
        ...previous,
        protocol: 'https:',
        host: 'localhost/',
        pathname: 'path',
        search: '?key=toto',
      };

      const replaceStateSpy = vi
        .spyOn(global.window.history, 'replaceState')
        .mockImplementation(() => {});

      saveValuesToPathQuery([{ key: 'key', value: 'value' }]);
      expect(replaceStateSpy).toHaveBeenCalledWith(
        { path: 'https://localhost/path?key=value' },
        '',
        'https://localhost/path?key=value',
      );
    });
    it('should replace values in query and push history', () => {
      global.window.location = {
        ...previous,
        protocol: 'https:',
        host: 'localhost/',
        pathname: 'path',
        search: '?key=toto',
      };

      const replaceStateSpy = vi
        .spyOn(global.window.history, 'replaceState')
        .mockImplementation(() => {});

      saveValuesToPathQuery([
        { key: 'key', value: 'value' },
        { key: 'key0', value: 'value0' },
      ]);
      expect(replaceStateSpy).toHaveBeenCalledWith(
        { path: 'https://localhost/path?key=value&key0=value0' },
        '',
        'https://localhost/path?key=value&key0=value0',
      );
    });
  });
});
