import { mount } from '@vue/test-utils';
import { useRouterHistory } from './router-history.composable';
import { defineComponent } from 'vue';
import { RouteLocationNamedRaw } from 'vue-router';

const pushMock = vi.fn();
vi.mock('vue-router', () => ({
  useRouter: vi.fn().mockImplementation(() => ({ push: pushMock })),
}));

const factory = (props?: any) => {
  return mount(
    defineComponent({
      setup() {
        return useRouterHistory();
      },
      template: '<div/>',
    }),
    { props: props },
  );
};

describe('Router History Composable', () => {
  beforeEach(() => {
    vi.resetAllMocks();
    console.warn = vi.fn();
  });
  describe('goBack', () => {
    const wrapper = factory();
    it('should throw error if no route in history', async () => {
      wrapper.vm.historyRoutes = [];
      try {
        await wrapper.vm.goBack();
      } catch (e) {
        expect(e).toBeTruthy();
        expect(console.warn).toHaveBeenCalled();
        expect(wrapper.vm.historyRoutes.length).toEqual(0);
      }
    });
    it('should throw error and reset history and go to fallback if available', async () => {
      wrapper.vm.historyRoutes = [
        {
          path: '/id0',
          name: 'id0',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        },
      ];
      try {
        await wrapper.vm.goBack({
          path: 'toto',
          name: 'toto',
          query: {},
          hash: '',
          params: {},
        } as any);
      } catch (e) {
        expect(e).toBeTruthy();
        expect(console.warn).not.toHaveBeenCalled();
        expect(wrapper.vm.historyRoutes.length).toEqual(0);
        expect(pushMock).toHaveBeenCalledWith({
          path: 'toto',
          name: 'toto',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        });
      }
    });
    it('should throw error and reset history and go to / if no fallback available', async () => {
      wrapper.vm.historyRoutes = [
        {
          path: '/id0',
          name: 'id0',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        },
      ];
      try {
        await wrapper.vm.goBack();
      } catch (e) {
        expect(e).toBeTruthy();
        expect(console.warn).not.toHaveBeenCalled();
        expect(wrapper.vm.historyRoutes.length).toEqual(0);
        expect(pushMock).toHaveBeenCalledWith({ path: '/' });
      }
    });
    it('should push route and remove corresponding historyRoutes', async () => {
      wrapper.vm.historyRoutes = [
        {
          path: '/id0',
          name: 'id0',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        },
        {
          path: '/id1',
          name: 'id1',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        },
        {
          path: '/id2',
          name: 'id2',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        },
      ];
      await wrapper.vm.goBack();
      expect(pushMock).toHaveBeenCalledWith({
        path: '/id1',
        name: 'id1',
        matched: [],
        fullPath: '',
        query: {},
        hash: '',
        meta: {},
        params: {},
        redirectedFrom: undefined,
      });
      expect(wrapper.vm.historyRoutes).toEqual([
        {
          path: '/id0',
          name: 'id0',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        },
      ]);
    });
  });
  describe('addHistoryRoute', () => {
    const wrapper = factory();
    it('should add history Route', () => {
      wrapper.vm.historyRoutes = [
        {
          path: '/id0',
          name: 'id0',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        },
      ];
      wrapper.vm.addHistoryRoute({
        path: '/id1',
        name: 'id1',
        matched: [],
        fullPath: '',
        query: {},
        hash: '',
        meta: {},
        params: {},
        redirectedFrom: undefined,
      });
      expect(wrapper.vm.historyRoutes).toEqual([
        {
          path: '/id0',
          name: 'id0',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        },
        {
          path: '/id1',
          name: 'id1',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        },
      ]);
    });
    it('should add history Route if empty', () => {
      wrapper.vm.historyRoutes = [];
      wrapper.vm.addHistoryRoute({
        path: '/id1',
        name: 'id1',
        matched: [],
        fullPath: '',
        query: {},
        hash: '',
        meta: {},
        params: {},
        redirectedFrom: undefined,
      });
      expect(wrapper.vm.historyRoutes).toEqual([
        {
          path: '/id1',
          name: 'id1',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        },
      ]);
    });
    it('should replace history Route if previous route has same name', () => {
      wrapper.vm.historyRoutes = [
        {
          path: '/id0',
          name: 'name0',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        },
      ];
      wrapper.vm.addHistoryRoute({
        path: '/id1',
        name: 'name0',
        matched: [],
        fullPath: '',
        query: {},
        hash: '',
        meta: {},
        params: {},
        redirectedFrom: undefined,
      });
      expect(wrapper.vm.historyRoutes).toEqual([
        {
          path: '/id1',
          name: 'name0',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        },
      ]);
    });
    it('should replace history Route if previous route has same path', () => {
      wrapper.vm.historyRoutes = [
        {
          path: '/id0',
          name: 'name0',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        },
      ];
      wrapper.vm.addHistoryRoute({
        path: '/id0',
        name: 'name1',
        matched: [],
        fullPath: '',
        query: {},
        hash: '',
        meta: {},
        params: {},
        redirectedFrom: undefined,
      });
      expect(wrapper.vm.historyRoutes).toEqual([
        {
          path: '/id0',
          name: 'name1',
          matched: [],
          fullPath: '',
          query: {},
          hash: '',
          meta: {},
          params: {},
          redirectedFrom: undefined,
        },
      ]);
    });
  });
});
