import { HttpModule } from "@nestjs/axios";
import { CacheModule, NotFoundException } from "@nestjs/common";
import { Test } from "@nestjs/testing";
import { PapersController } from "src/application";
import { SearchService } from "src/core/services/common/search.service";


describe('Unit tests for PapersController', () => {
    let searchService: SearchService;
    let papersController: PapersController;

    beforeAll(async () => {
        const moduleRef = await Test.createTestingModule({
            providers: [
                PapersController,
                {
                    provide: SearchService,
                    useValue: {
                        findByContext: jest.fn(),
                        findByID: jest.fn()
                    }
                }
            ],
            imports: [
                HttpModule,
                CacheModule.register()
            ]
        }).compile();

        papersController = moduleRef.get(PapersController);
        searchService = moduleRef.get(SearchService);
    });

    it('Should be defined', () => {
        expect(papersController).toBeDefined();
        expect(searchService).toBeDefined();
    });

    describe('getByContext()', () => {
        it('Should touch SearchService.findByContext() method', () => {
            let findCtxMock = jest.spyOn(searchService, 'findByContext')
                .mockResolvedValueOnce({
                    took: undefined,
                    timed_out: undefined,
                    hits: undefined,
                    _shards: undefined,
                });

            papersController.getByContext({ query: undefined });
            expect(findCtxMock).toHaveBeenCalled();
        });

        it('Should resolve, when searched successfully', () => {
            const searchResultMock = {
                took: 1,
                timed_out: false,
                hits: {
                    total: {},
                    hits: [
                        {
                            _source: {
                                id: 'thisIsID',
                                title: 'andThisIsTheTitle',
                                authors: ['alsoAuthors'],
                                topic: 'andThatIsTheTopic',
                                summary: 'someSummaries',
                                tags: ['tag1', 'tag2'],
                                content: 'finallyContent!'
                            }
                        }
                    ],
                },
                _shards: undefined,
            };

            jest.spyOn(searchService, 'findByContext')
                .mockResolvedValueOnce(searchResultMock);
            
            expect(papersController.getByContext({ query: undefined })).resolves.toEqual(searchResultMock);
        });

        it('Should throw, when search was unsuccessful', () => {
            searchService.findByContext = jest.fn()
                .mockRejectedValueOnce(new NotFoundException);

            expect(papersController.getByContext({ query: undefined }))
                .rejects.toThrow(NotFoundException)
        });
    });

    describe('getByID()', () => {
        it('Should touch SearchService.findByID() method', () => {
            let findIDMock = jest.spyOn(searchService, 'findByID')
                .mockResolvedValueOnce({
                    took: undefined,
                    timed_out: undefined,
                    hits: { total: {}, hits:[{ _source: undefined }] },
                    _shards: undefined,
                });
            
            papersController.getByID('');
            expect(findIDMock).toHaveBeenCalled();
        });

        it('Should resolve the document, when searched successfully', () => {
            const searchResultMock = {
                took: 1,
                timed_out: false,
                hits: {
                    total: {},
                    hits: [
                        {
                            _source: {
                                id: 'thisIsID',
                                title: 'andThisIsTheTitle',
                                authors: ['alsoAuthors'],
                                topic: 'andThatIsTheTopic',
                                summary: 'someSummaries',
                                tags: ['tag1', 'tag2'],
                                content: 'finallyContent!'
                            }
                        }
                    ],
                },
                _shards: undefined,
            };

            jest.spyOn(searchService, 'findByID')
                .mockResolvedValueOnce(searchResultMock);

            expect(papersController.getByID(''))
                .resolves.toEqual(searchResultMock.hits.hits[0]._source);
        });

        it('Should throw, when search was unsuccessful', () => {
            searchService.findByID = jest.fn()
                .mockRejectedValueOnce(new NotFoundException);

            expect(papersController.getByID(''))
                .rejects.toThrow(NotFoundException)
        });
    });
});