import { Role } from '../../../domain/types/role.enum';
import { Geography } from '../../../domain/entities/geography';
import { Coordinate } from '../../../../geography/domain/entities/coordinate';
import { IGeorouter } from '../../../../geography/domain/interfaces/georouter.interface';
import { GeorouterSettings } from '../../../../geography/domain/types/georouter-settings.type';
import { Route } from '../../../../geography/domain/entities/route';
import { IGeodesic } from '../../../../geography/domain/interfaces/geodesic.interface';

const simpleCoordinates: Coordinate[] = [
  {
    lon: 6,
    lat: 47,
  },
  {
    lon: 6.1,
    lat: 47.1,
  },
];

const complexCoordinates: Coordinate[] = [
  {
    lon: 6,
    lat: 47,
  },
  {
    lon: 6.1,
    lat: 47.1,
  },
  {
    lon: 6.2,
    lat: 47.2,
  },
];

const mockGeodesic: IGeodesic = {
  inverse: jest.fn(),
};

const driverRoute: Route = new Route(mockGeodesic);
driverRoute.distance = 25000;

const commonRoute: Route = new Route(mockGeodesic);
commonRoute.distance = 20000;

const mockGeorouter: IGeorouter = {
  route: jest
    .fn()
    .mockResolvedValueOnce([
      {
        key: 'driver',
        route: driverRoute,
      },
    ])
    .mockResolvedValueOnce([
      {
        key: 'passenger',
        route: commonRoute,
      },
    ])
    .mockResolvedValueOnce([
      {
        key: 'common',
        route: commonRoute,
      },
    ])
    .mockResolvedValueOnce([
      {
        key: 'driver',
        route: driverRoute,
      },
      {
        key: 'passenger',
        route: commonRoute,
      },
    ]),
};

const georouterSettings: GeorouterSettings = {
  withDistance: false,
  withPoints: true,
  withTime: false,
};

describe('Geography entity', () => {
  it('should be defined', () => {
    expect(new Geography(simpleCoordinates)).toBeDefined();
  });

  it('should create a route as driver', async () => {
    const geography = new Geography(complexCoordinates);
    await geography.createRoutes(
      [Role.DRIVER],
      mockGeorouter,
      georouterSettings,
    );
    expect(geography.driverRoute).toBeDefined();
    expect(geography.passengerRoute).toBeUndefined();
    expect(geography.driverRoute.distance).toBe(25000);
  });

  it('should create a route as passenger', async () => {
    const geography = new Geography(simpleCoordinates);
    await geography.createRoutes(
      [Role.PASSENGER],
      mockGeorouter,
      georouterSettings,
    );
    expect(geography.driverRoute).toBeUndefined();
    expect(geography.passengerRoute).toBeDefined();
    expect(geography.passengerRoute.distance).toBe(20000);
  });

  it('should create routes as driver and passenger with simple coordinates', async () => {
    const geography = new Geography(simpleCoordinates);
    await geography.createRoutes(
      [Role.DRIVER, Role.PASSENGER],
      mockGeorouter,
      georouterSettings,
    );
    expect(geography.driverRoute).toBeDefined();
    expect(geography.passengerRoute).toBeDefined();
    expect(geography.driverRoute.distance).toBe(20000);
    expect(geography.passengerRoute.distance).toBe(20000);
  });

  it('should create routes as driver and passenger with complex coordinates', async () => {
    const geography = new Geography(complexCoordinates);
    await geography.createRoutes(
      [Role.DRIVER, Role.PASSENGER],
      mockGeorouter,
      georouterSettings,
    );
    expect(geography.driverRoute).toBeDefined();
    expect(geography.passengerRoute).toBeDefined();
    expect(geography.driverRoute.distance).toBe(25000);
    expect(geography.passengerRoute.distance).toBe(20000);
  });
});