import { shallow, mount } from 'enzyme';
import React from 'react';
import ReactDOM from 'react-dom';
import { Manifest } from 'web-foundation';

describe('Manifest', function() {
    it('should calculate subtotals', function() {
        const model = new Manifest.Model({
            items: [ {
                description: 'pinto',
                qty: 2,
                price: 12.01
            } ]
        });

        expect(model.subtotal()).to.equal(24.02);

        model.items.push({
            description: 'kidney',
            qty: 3,
            price: 0.367
        });

        expect(model.subtotal()).to.equal(25.121);
    });

    it('should calculate taxes', function() {
        const model = new Manifest.Model({
            items: [ {
                description: 'pinto',
                qty: 2,
                price: 12.3
            } ]
        });

        expect(model.tax()).to.equal(0);
        expect(model.tax(0.14)).to.equal(3.4440000000000004);
    });

    it('should calculate the total', function() {
        const model = new Manifest.Model({
            items: [ {
                description: 'pinto',
                qty: 2,
                price: 12.3
            } ]
        });

        expect(model.total()).to.equal(24.6);
        expect(model.total(0.14)).to.equal(28.044);
    });

    it('should format manifest items', function() {
        const model = new Manifest.Model();

        expect(model.asManifest()).to.equal('');

        model.items.push({
            description: 'pinto',
            qty: 2,
            price: 12.3
        });

        expect(model.asManifest()).to.equal('2 x pinto @ $12.30');

        model.items.push({
            description: 'kidney',
            qty: 6,
            price: 0.2343
        });

        expect(model.asManifest())
            .to.equal('2 x pinto @ $12.30\n6 x kidney @ $0.23');
    });
});

describe('<Manifest />', function() {
    it('should dry run', function() {
        const wrapper = shallow(<Manifest.View />),
            wrapperMounted = mount(<Manifest.View />);

        expect(wrapper.hasClass('manifest')).to.be.true;
        expect(wrapper.find('.header').is('.row.t50-16-16-16'))
            .to.be.true;
        expect(wrapper.find('.header').children()).to.have.length(4);

        expect(wrapper.find('.error')).to.have.length(0);
        expect(wrapper.find('.summary')).to.have.length(0);

        expect(wrapperMounted.find('label')).to.have.length(1);
        expect(wrapperMounted.find('label').text()).to.equal('Order ID');

        expect(wrapperMounted.find('.manifest-item')).to.have.length(1);
    });

    it('should hide the price', function() {
        const wrapper = shallow(<Manifest.View hidePrice />),
            wrapperMounted = mount(<Manifest.View hidePrice />);

        expect(wrapper.find('.header').is('.row.t50-50'))
            .to.be.true;
        expect(wrapper.find('.header').children()).to.have.length(2);

        expect(wrapperMounted.find('.manifest-item')).to.have.length(1);
        expect(wrapperMounted.find('.manifest-item').find('input'))
            .to.have.length(2);
    });

    it('should display errors', function() {
        const wrapper = mount(<Manifest.View />);

        wrapper.instance().model.errors = {
            required: 'This field is required'
        };

        wrapper.instance().forceUpdate();

        expect(wrapper.find('.error')).to.have.length(1);
        expect(wrapper.find('.error').text())
            .to.equal('This field is required');
    });

    it('should show some items', function() {
        const model = new Manifest.Model({
                items: [ {
                    description: 'pinto',
                    qty: 2,
                    price: 12.3
                }, {
                    description: 'kidney',
                    qty: 6,
                    price: 2.3
                }, {
                    description: 'navy',
                    qty: 1,
                    price: 4.758
                }, {
                    description: 'soy',
                    qty: 3,
                    price: 1.25
                } ]
            }),
            wrapper = mount(<Manifest.View model={ model } />);

        expect(wrapper.find('.manifest-item')).to.have.length(5);
        expect(wrapper.find('.summary')).to.have.length(1);
        expect(wrapper.find('.summary').find('.amount').at(0).text())
            .to.equal('$46.91');
        expect(wrapper.find('.summary').find('.amount').at(1).text())
            .to.equal('$3.75');
        expect(wrapper.find('.summary').find('.amount').at(2).text())
            .to.equal('$50.66');
    });

    it('should remove items', function() {
        const model = new Manifest.Model({
                items: [ {
                    description: 'pinto',
                    qty: 2,
                    price: 12.3
                }, {
                    description: 'kidney',
                    qty: 6,
                    price: 2.3
                }, {
                    description: 'navy',
                    qty: 1,
                    price: 4.758
                }, {
                    description: 'soy',
                    qty: 3,
                    price: 1.25
                } ]
            }),
            wrapper = mount(<Manifest.View model={ model } />);

        expect(wrapper.find('.manifest-item')).to.have.length(5);

        wrapper.find('.manifest-item').at(1).find('.remove')
            .simulate('click');
        wrapper.instance().forceUpdate();

        expect(wrapper.find('.manifest-item')).to.have.length(4);
        expect(model.items).to.have.length(3);
        expect(model.items[1].description).to.equal('navy');
    });

    it('should add items', function() {
        const model = new Manifest.Model({
                items: [ {
                    description: 'pinto',
                    qty: 2,
                    price: 12.3
                }, {
                    description: 'kidney',
                    qty: 6,
                    price: 2.3
                }, {
                    description: 'navy',
                    qty: 1,
                    price: 4.758
                } ]
            }),
            wrapper = mount(<Manifest.View model={ model } />),
            node = ReactDOM.findDOMNode(wrapper.instance());

        expect(wrapper.find('.manifest-item')).to.have.length(4);

        model.errors = { required: 'beans' };
        node.getElementsByClassName('manifest-item')[3]
            .getElementsByTagName('input')[0]
            .value = 'soy';

        wrapper.instance().add();

        wrapper.instance().forceUpdate();

        expect(wrapper.find('.manifest-item')).to.have.length(5);
        expect(node
            .getElementsByClassName('manifest-item')[4]
            .getElementsByTagName('input')[0]
            .value
        ).to.equal('');
    });
});

describe('ManifestItem', function() {
    it('should return null for messed up totals', function() {
        const model = new Manifest.ItemModel({
            description: 'beans'
        });

        expect(model.total()).to.be.null;

        model.qty = 3;

        expect(model.total()).to.be.null;

        model.price = 4;

        expect(model.total()).to.equal(12);
    });

    it('should ignore stuff in the manifest line', function() {
        const model = new Manifest.ItemModel({
            description: 'beans'
        });

        expect(model.asLine()).to.equal('beans');

        model.qty = 3;

        expect(model.asLine()).to.equal('3 x beans');

        model.price = 4;

        expect(model.asLine()).to.equal('3 x beans @ $4.00');

        model.qty = null;

        expect(model.asLine()).to.equal('beans @ $4.00');
    });
});

describe('<ManifestItem />', function() {
    it('should dry load', function() {
        const wrapper = shallow(<Manifest.ItemView />),
            wrapperMounted = mount(<Manifest.ItemView />);

        expect(wrapper.hasClass('manifest-item')).to.be.true;
        expect(wrapper.hasClass('t50-16-16-16')).to.be.true;
        expect(wrapper.find('.remove')).to.have.length(0);

        expect(wrapperMounted.find('input')).to.have.length(3);
        expect(wrapperMounted.find('.total')).to.have.length(1);
        expect(wrapperMounted.find('.total').text())
            .to.equal('$0.00');
    });

    it('should be removable', function() {
        const spy = sinon.spy(),
            wrapper = mount(
                <Manifest.ItemView onClose={ spy } />
            );

        expect(wrapper.find('.remove')).to.have.length(1);

        wrapper.find('.remove').simulate('click');

        expect(spy.callCount).to.equal(1);
    });

    it('should check satisfaction', function() {
        const spy = sinon.spy(),
            wrapper = mount(
                <Manifest.ItemView fieldChange={ spy } />
            );

        wrapper.instance().checkMySatisfaction();

        expect(spy.callCount).to.equal(0);

        wrapper.instance().model.price = 12;
        wrapper.instance().checkMySatisfaction();
        expect(spy.callCount).to.equal(1);
        expect(spy.getCall(0).args[0]).to.equal('price');

        wrapper.instance().model.qty = 2;
        wrapper.instance().checkMySatisfaction();
        expect(spy.callCount).to.equal(2);
        expect(spy.getCall(1).args[0]).to.equal('qty');

        wrapper.instance().model.description = 'beans';
        wrapper.instance().checkMySatisfaction();
        expect(spy.callCount).to.equal(3);
        expect(spy.getCall(2).args[0]).to.equal('description');
    });
});
