import './index.js';

describe('Ticket', () => {
    describe('Component vnTicketBasicDataStepOne', () => {
        let controller;
        let $httpBackend;
        let $httpParamSerializer;

        beforeEach(ngModule('ticket'));

        beforeEach(inject(($componentController, _$httpBackend_, _$httpParamSerializer_) => {
            $httpBackend = _$httpBackend_;
            $httpParamSerializer = _$httpParamSerializer_;
            const $element = angular.element('<vn-ticket-basic-data-step-one></vn-ticket-basic-data-step-one>');
            controller = $componentController('vnTicketBasicDataStepOne', {$element});
            controller.ticket = {
                addressFk: 121,
                agencyModeFk: 7,
                warehouseFk: 1
            };
        }));

        describe('ticket() setter', () => {
            it('should set ticket property and call clientAddressesList() method', () => {
                jest.spyOn(controller, 'clientAddressesList');
                controller.ticket = {id: 1, clientFk: 1101};

                expect(controller.clientAddressesList).toHaveBeenCalledWith(1101);
            });

            it(`should not call clientAddressesList() method as the ticket doesn't have an ID`, () => {
                jest.spyOn(controller, 'clientAddressesList');
                controller.ticket = {};

                expect(controller.clientAddressesList).not.toHaveBeenCalledWith();
            });
        });

        describe('clientId() getter', () => {
            it('should return the clientFk property', () => {
                controller.ticket = {id: 1, clientFk: 1102};

                expect(controller.clientId).toEqual(1102);
            });
        });

        describe('clientId() setter', () => {
            it('should set clientId property and call clientAddressesList() method ', () => {
                jest.spyOn(controller, 'clientAddressesList');
                controller.ticket = {id: 1, clientId: 1101};
                controller.clientId = 1102;

                expect(controller.clientAddressesList).toHaveBeenCalledWith(1102);
            });
        });

        describe('adressId() getter', () => {
            it('should return the addressFk property', () => {
                controller.ticket = {id: 1, addressFk: 99};

                expect(controller.addressId).toEqual(99);
            });
        });

        describe('addressId() setter', () => {
            it('should set addressId property and call getShipped() method ', () => {
                jest.spyOn(controller, 'getShipped');
                controller.ticket.addressFk = 99;
                controller.addressId = 100;
                const landed = Date.vnNew();
                const expectedResult = {
                    landed: landed,
                    addressFk: 100,
                    agencyModeFk: 7,
                    warehouseFk: 1
                };
                controller.landed = landed;

                expect(controller.getShipped).toHaveBeenCalledWith(expectedResult);
                expect(controller.ticket.addressFk).toEqual(100);
            });
        });

        describe('warehouseId() getter', () => {
            it('should return the warehouseId property', () => {
                controller.ticket.warehouseFk = 2;

                expect(controller.warehouseId).toEqual(2);
            });
        });

        describe('warehouseId() setter', () => {
            it('should set warehouseId property and call getShipped() method ', () => {
                jest.spyOn(controller, 'getShipped');
                controller.ticket.warehouseId = 1;
                controller.warehouseId = 2;

                expect(controller.ticket.warehouseFk).toEqual(2);
            });
        });

        describe('shipped() getter', () => {
            it('should return the shipped property', () => {
                const shipped = Date.vnNew();
                controller.ticket.shipped = shipped;

                expect(controller.shipped).toEqual(shipped);
            });
        });

        describe('shipped() setter', () => {
            it('should set shipped property and call getLanded() method ', () => {
                jest.spyOn(controller, 'getLanded');
                const shipped = Date.vnNew();
                const expectedResult = {
                    shipped: shipped,
                    addressFk: 121,
                    agencyModeFk: 7,
                    warehouseFk: 1
                };
                controller.shipped = shipped;

                expect(controller.getLanded).toHaveBeenCalledWith(expectedResult);
            });
        });

        describe('landed() getter', () => {
            it('should return the landed property', () => {
                const landed = Date.vnNew();
                controller.ticket.landed = landed;

                expect(controller.landed).toEqual(landed);
            });
        });

        describe('landed() setter', () => {
            it('should set shipped property and call getShipped() method ', () => {
                jest.spyOn(controller, 'getShipped');
                const landed = Date.vnNew();
                const expectedResult = {
                    landed: landed,
                    addressFk: 121,
                    agencyModeFk: 7,
                    warehouseFk: 1
                };
                controller.landed = landed;

                expect(controller.getShipped).toHaveBeenCalledWith(expectedResult);
            });
        });

        describe('agencyModeId() getter', () => {
            it('should return the agencyModeFk property', () => {
                controller.ticket.agencyModeFk = 66;

                expect(controller.agencyModeId).toEqual(66);
            });
        });

        describe('agencyModeId() setter', () => {
            it('should set agencyModeId property and call getLanded() method', () => {
                jest.spyOn(controller, 'getLanded');
                controller.$.agencyMode = {selection: {warehouseFk: 1}};
                const shipped = Date.vnNew();
                const agencyModeId = 8;
                const expectedResult = {
                    shipped: shipped,
                    addressFk: 121,
                    agencyModeFk: agencyModeId,
                    warehouseFk: 1
                };
                controller.ticket.shipped = shipped;
                controller.agencyModeId = 8;

                expect(controller.getLanded).toHaveBeenCalledWith(expectedResult);
            });

            it('should do nothing if attempting to set the same agencyMode id', () => {
                jest.spyOn(controller, 'getShipped');
                const landed = Date.vnNew();
                const agencyModeId = 7;
                const expectedResult = {
                    landed: landed,
                    addressFk: 121,
                    agencyModeFk: agencyModeId,
                    warehouseFk: 1
                };
                controller.ticket.landed = landed;
                controller.agencyModeId = 7;

                expect(controller.getShipped).not.toHaveBeenCalledWith(expectedResult);
            });
        });

        describe('zoneId() getter', () => {
            it('should return the zoneFk property', () => {
                controller.ticket.zoneFk = 10;

                expect(controller.zoneId).toEqual(10);
            });
        });

        describe('zoneId() setter', () => {
            it('should set zoneId property and call onChangeZone() method ', () => {
                const zoneId = 5;
                jest.spyOn(controller, 'onChangeZone');
                controller.ticket = {id: 1};
                controller.zoneId = 5;

                expect(controller.onChangeZone).toHaveBeenCalledWith(zoneId);
            });

            it('should do nothing if attempting to set the same zone id', () => {
                const zoneId = 5;
                jest.spyOn(controller, 'onChangeZone');
                controller.ticket = {id: 1, zoneFk: zoneId};
                controller.zoneId = zoneId;

                expect(controller.onChangeZone).not.toHaveBeenCalledWith(zoneId);
            });
        });

        describe('clientAddressesList()', () => {
            it('should return a list of addresses from choosed client', async() => {
                const clientId = 1102;
                let filter = {
                    include: [
                        {
                            relation: 'province',
                            scope: {
                                fields: ['name']
                            }
                        },
                        {
                            relation: 'agencyMode',
                            scope: {
                                fields: ['name']
                            }
                        }
                    ]
                };
                filter = encodeURIComponent(JSON.stringify(filter));

                $httpBackend.expect('GET', `Clients/${clientId}/addresses?filter=${filter}`).respond(200);
                controller.clientAddressesList(clientId);
                $httpBackend.flush();
            });
        });

        describe('getClientDefaultAddress()', () => {
            it('should return the default address from choosed client', async() => {
                const clientId = 1102;

                $httpBackend.expect('GET', `Clients/${clientId}`).respond(200);
                controller.getClientDefaultAddress(clientId);
                $httpBackend.flush();
            });
        });

        describe('onChangeZone()', () => {
            it('should return an available zone', async() => {
                const zoneId = 5;
                const agencyModeFk = 8;
                $httpBackend.expect('GET', `Zones/${zoneId}`).respond(200, {agencyModeFk});
                controller.onChangeZone(zoneId);
                $httpBackend.flush();

                expect(controller.ticket.agencyModeFk).toEqual(agencyModeFk);
            });
        });

        describe('isFormInvalid()', () => {
            it('should check if all form fields are valid', () => {
                controller.ticket = {
                    clientFk: 1,
                    addressFk: 121,
                    zoneFk: 3,
                    agencyModeFk: 1,
                    companyFk: 442,
                    warehouseFk: 1,
                    shipped: Date.vnNew(),
                    landed: Date.vnNew()
                };

                expect(controller.isFormInvalid()).toBeFalsy();
            });
        });

        describe('onStepChange()', () => {
            it('should call onStepChange method and return a NO_AGENCY_AVAILABLE signal error', async() => {
                let landed = Date.vnNew();
                landed.setHours(0, 0, 0, 0);

                controller._ticket = {
                    id: 1,
                    clientFk: 1,
                    addressFk: 121,
                    zoneFk: 3,
                    agencyModeFk: 1,
                    companyFk: 442,
                    warehouseFk: 1,
                    shipped: Date.vnNew(),
                    landed: landed
                };

                let response = {error: new Error('NO_AGENCY_AVAILABLE')};

                $httpBackend.whenPOST(`tickets/1/priceDifference`).respond(400, response);
                $httpBackend.expectPOST(`tickets/1/priceDifference`);
                controller.onStepChange();
                $httpBackend.flush();
            });
        });

        describe('getLanded()', () => {
            it('should return an available landed date', async() => {
                const shipped = Date.vnNew();
                const expectedResult = {landed: Date.vnNew()};
                const params = {
                    shipped: shipped,
                    addressFk: 121,
                    agencyModeFk: 7,
                    warehouseFk: 1
                };
                const serializedParams = $httpParamSerializer(params);
                controller.ticket.shipped = shipped;

                $httpBackend.expect('GET', `Agencies/getLanded?${serializedParams}`).respond(200, expectedResult);
                controller.getLanded(params);
                $httpBackend.flush();

                expect(controller.shipped).toEqual(shipped);
                expect(controller.landed).toEqual(expectedResult.landed);
            });
        });

        describe('getShipped()', () => {
            it('should return an available shipped date', async() => {
                const landed = Date.vnNew();
                const expectedResult = {shipped: Date.vnNew()};
                const params = {
                    landed: landed,
                    addressFk: 121,
                    agencyModeFk: 7,
                    warehouseFk: 1
                };
                const serializedParams = $httpParamSerializer(params);
                controller.ticket.landed = landed;

                $httpBackend.expect('GET', `Agencies/getShipped?${serializedParams}`).respond(200, expectedResult);
                controller.getShipped(params);
                $httpBackend.flush();

                expect(controller.shipped).toEqual(expectedResult.shipped);
                expect(controller.landed).toEqual(landed);
            });
        });

        describe('zoneWhere() getter', () => {
            it('should return an object containing filter properties', async() => {
                const shipped = Date.vnNew();
                controller.ticket.shipped = shipped;

                const expectedResult = {
                    addressFk: 121,
                    agencyModeFk: 7,
                    shipped: shipped,
                    warehouseFk: 1
                };
                const result = controller.zoneWhere();

                expect(result).toEqual(expect.objectContaining(expectedResult));
            });
        });

        describe('agencyModeWhere() getter', () => {
            it('should return an object containing the warehouseFk property', async() => {
                const expectedResult = {warehouseFk: 1};
                const result = controller.agencyModeWhere();

                expect(result).toEqual(expect.objectContaining(expectedResult));
            });
        });
    });
});