import { TestBed } from '@angular/core/testing';
import { getDictionariesServiceMock } from '@modules/components/page-filters/services/dictionaries-service.mock';
import { DictionariesService } from '@modules/components/page-filters/services/dictionaries-service';
import { Language } from '@shared/enumerators';
import { sortStrings } from '@shared/helpers/sorterts';
import { LocalizationService } from '@shared/services';

import { CitiesSearchService } from './cities-search.service';

describe('CitiesSearchService', () => {
    let service: CitiesSearchService;
    let dictService: DictionariesService;
    let localizationService: LocalizationService;

    beforeEach(async () => {
        dictService = getDictionariesServiceMock();
        localizationService = {
            Language: Language.ru,
        } as any;

        TestBed.configureTestingModule({
            providers: [
                CitiesSearchService,
                { provide: LocalizationService, useValue: localizationService },
                { provide: DictionariesService, useValue: dictService },
            ],
        });
        service = TestBed.inject(CitiesSearchService);

        await dictService.ready$;
    });

    it('should sort results', () => {
        const input = 'М';
        const result = service.findCitiesByNameUnprocessed(input);
        const citiesNames = result.map((city) => city.name);
        const citiesNamesSorted = citiesNames.sort(sortStrings);

        expect(citiesNamesSorted).toEqual(citiesNames);
    });

    it('should return 10 cities that start with "М"', () => {
        const input = 'М';
        const result = service.findCitiesByNameUnprocessed(input);

        expect(result.length).toBe(11);

        for (const item of result) {
            expect(item.name[0]).toBe(input);
        }
    });

    it('should return 3 cities. First should start with "Мо", other should include it', () => {
        const input = 'Мо';
        const inputLowerCase = input.toLowerCase();

        const result = service.findCitiesByNameUnprocessed(input);

        expect(result.length).toBe(3);

        const names = result.map((city) => city.name.toLowerCase());
        expect(names[0].indexOf(inputLowerCase)).toBe(0);
        expect(names[1].indexOf(inputLowerCase)).not.toBe(0);
        expect(names[1].includes(inputLowerCase)).toBeTruthy();
        expect(names[2].indexOf(inputLowerCase)).not.toBe(0);
        expect(names[2].includes(inputLowerCase)).toBeTruthy();
    });

    it('should return Moscow for "Мос" input', () => {
        const input = 'Мос';

        const result = service.findCitiesByNameUnprocessed(input);

        expect(result.length).toBe(1);

        expect(result[0].name).toBe('Москва');
    });

    it('should be case insensitive', () => {
        function assertResult(input: string) {
            const result = service.findCitiesByNameUnprocessed(input);

            expect(result.length).toBe(1);
            expect(result[0].name).toBe('Москва');
        }

        assertResult('Мос');
        assertResult('МОС');
        assertResult('МоС');
    });

    it('should add airports to found city', () => {
        const input = 'Мос';
        const result = service.findCitiesByName(input);

        expect(result.length).toBe(3);
        expect(result[0].name).toBe('Москва');
        expect(result[1].name).toBe('Внуково');
        expect(result[2].name).toBe('Шереметьево');
    });

    it('should find city by city code', () => {
        const code = 'MOW';
        const result = service.findCitiesByCode(code);

        expect(result.length).toBe(3);
        expect(result[0].name).toBe('Москва');
        expect(result[1].name).toBe('Внуково');
        expect(result[2].name).toBe('Шереметьево');
    });

    it('should find city by airport code', () => {
        const code = 'VKO';
        const result = service.findCitiesByAirportCode(code);

        expect(result.length).toBe(3);
        expect(result[0].name).toBe('Москва');
        expect(result[1].name).toBe('Внуково');
        expect(result[2].name).toBe('Шереметьево');
    });
});
