/** @odoo-module */

import { click, getFixture, nextTick, patchWithCleanup } from '@web/../tests/helpers/utils';
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";

import { LunchKanbanRenderer } from '@lunch/views/kanban';

let target;
let serverData;
let lunchInfos;

async function makeLunchView(extraArgs = {}) {
    return await makeView(
        Object.assign({
            serverData,
            type: "kanban",
            resModel: "lunch.product",
            arch: `
            <kanban js_class="lunch_kanban">
                <templates>
                    <t t-name="kanban-box">
                        <div>
                            <field name="name"/>
                            <field name="price"/>
                        </div>
                    </t>
                </templates>
            </kanban>`,
            mockRPC: (route, args) => {
                if (route == '/lunch/user_location_get') {
                    return Promise.resolve(serverData.models['lunch.location'].records[0].id);
                } else if (route == '/lunch/infos') {
                    return Promise.resolve(lunchInfos);
                }
            }
        }, extraArgs
    ));
}

QUnit.module('Lunch', {}, function() {
QUnit.module('LunchKanban', (hooks) => {
    hooks.beforeEach(() => {
        target = getFixture();
        serverData = {
            models: {
                'lunch.product': {
                    fields: {
                        id: { string: "ID", type: "integer" },
                        name: { string: 'Name', type: 'char' },
                        is_available_at: { string: 'Available', type: 'integer' },
                        price: { string: 'Price', type: 'float', },
                    },
                    records: [
                        { id: 1, name: "Big Plate", is_available_at: 1, price: 4.95, },
                        { id: 2, name: "Small Plate", is_available_at: 2, price: 6.99, },
                        { id: 3, name: "Just One Plate", is_available_at: 2, price: 5.87, },
                    ]
                },
                'lunch.location': {
                    fields: {
                        name: { string: 'Name', type: 'char' },
                    },
                    records: [
                        { id: 1, name: "Old Office" },
                        { id: 2, name: "New Office" },
                    ]
                },
                'lunch.order': {
                    fields: {
                        product_id: { string: 'Product', type: 'many2one', relation: 'lunch.product', },
                    }
                },
                'res.users': {
                    fields: {
                        share: { type: 'boolean', },
                    },
                    records: [
                        { id: 1, name: 'Johnny Hache', share: false, },
                        { id: 2, name: 'David Elora', share: false, }
                    ]
                }
            },
            views: {
                'lunch.order,false,form': `<form>
                        <sheet>
                            <field name="product_id" readonly="1"/>
                        </sheet>
                        <footer>
                            <button name="add_to_cart" type="object" string="Add to cart" />
                            <button string="Discard" special="cancel"/>
                        </footer>
                    </form>`
            }
        };
        lunchInfos = {
            username: "Johnny Hache",
            wallet: 12.05,
            is_manager: false,
            currency: {
                symbol: "€",
                position: "after",
            },
            user_location: [1, "Old Office"],
            alerts: [],
            lines: [],
        };

        setupViewRegistries();
    });

    QUnit.test("Basic rendering", async function (assert) {
        assert.expect(4);

        await makeLunchView();

        assert.containsOnce(target, '.o_lunch_banner');
        assert.containsNone(target, '.o_lunch_content .alert');
        assert.containsOnce(target, '.o_kanban_record:not(.o_kanban_ghost)', 1);

        const lunchDashboard = target.querySelector('.o_lunch_banner');
        const lunchUser = lunchDashboard.querySelector('.lunch_user span');
        assert.equal(lunchUser.innerText, 'Johnny Hache');
    });

    QUnit.test("Open product", async function (assert) {
        assert.expect(2);

        await makeLunchView();

        patchWithCleanup(LunchKanbanRenderer.prototype, {
            openOrderLine(productId, orderId) {
                assert.equal(productId, 1);
            }
        });

        assert.containsOnce(target, '.o_kanban_record:not(.o_kanban_ghost)');

        click(target, '.o_kanban_record:not(.o_kanban_ghost)');
    });

    QUnit.test("Basic rendering with alerts", async function (assert) {
        assert.expect(2);

        let userInfos = {
            ...lunchInfos,
            alerts: [
                {
                    id: 1,
                    message: '<b>free boudin compote for everyone</b>',
                }
            ]
        };
        await makeLunchView({
            mockRPC: (route, args) => {
                if (route == '/lunch/user_location_get') {
                    return Promise.resolve(userInfos.user_location[0]);
                } else if (route == '/lunch/infos') {
                    return Promise.resolve(userInfos);
                }
            }
        });

        assert.containsOnce(target, '.o_lunch_content .alert');
        assert.equal(target.querySelector('.o_lunch_content .alert').innerText, 'free boudin compote for everyone');
    });

    QUnit.test("Open product", async function (assert) {
        assert.expect(2);

        await makeLunchView();

        patchWithCleanup(LunchKanbanRenderer.prototype, {
            openOrderLine(productId, orderId) {
                assert.equal(productId, 1);
            }
        });

        assert.containsOnce(target, '.o_kanban_record:not(.o_kanban_ghost)');

        click(target, '.o_kanban_record:not(.o_kanban_ghost)');
    });

    QUnit.test("Location change", async function (assert) {
        assert.expect(3);

        let userInfos = { ...lunchInfos };
        await makeLunchView({
            mockRPC: (route, args) => {
                if (route == '/lunch/user_location_get') {
                    return Promise.resolve(userInfos.user_location[0]);
                } else if (route == '/lunch/infos') {
                    return Promise.resolve(userInfos);
                } else if (route == '/lunch/user_location_set') {
                    assert.equal(args.location_id, 2);
                    userInfos.user_location = [2, "New Office"];
                    return Promise.resolve(true);
                }
            }
        });

        click(target, '.lunch_location input');

        await nextTick();
        assert.containsOnce(target, '.lunch_location .dropdown-item:contains(New Office)');

        click(target, '.lunch_location li:not(.o_m2o_dropdown_option) .dropdown-item:not(.ui-state-active)');

        await nextTick();
        assert.containsN(target, 'div[role=article].o_kanban_record', 2);
    });

    QUnit.test("Manager: user change", async function (assert) {
        assert.expect(8);

        let userInfos = { ...lunchInfos, is_manager: true };
        let expectedUserId = false; // false as we are requesting for the current user
        await makeLunchView({
            mockRPC: (route, args) => {
                if (route == '/lunch/user_location_get') {
                    return Promise.resolve(userInfos.user_location[0]);
                } else if (route == '/lunch/infos') {
                    assert.equal(expectedUserId, args.user_id);

                    if (expectedUserId === 2) {
                        userInfos = {
                            ...userInfos,
                            username: 'David Elora',
                            wallet: -10000,
                        };
                    }

                    return Promise.resolve(userInfos);
                } else if (route == '/lunch/user_location_set') {
                    assert.equal(args.location_id, 2);
                    userInfos.user_location = [2, "New Office"];
                    return Promise.resolve(true);
                }
            }
        });

        assert.containsOnce(target, '.lunch_user input');
        click(target, '.lunch_user input');

        await nextTick();
        assert.containsOnce(target, '.lunch_user .dropdown-item:contains(David Elora)');

        expectedUserId = 2;
        click(target, '.lunch_user li:not(.o_m2o_dropdown_option) .dropdown-item:not(.ui-state-active)');

        await nextTick();
        const wallet = target.querySelector('.o_lunch_banner .col-9 > .d-flex > span:nth-child(2)');
        assert.equal(wallet.innerText, '-10000.00€', 'David Elora is poor')

        click(target, '.lunch_location input');
        await nextTick();
        click(target, '.lunch_location li:not(.o_m2o_dropdown_option) .dropdown-item:not(.ui-state-active)');

        await nextTick();
        const user = target.querySelector('.lunch_user input');
        assert.equal(user.value, 'David Elora', 'changing location should not reset user');
    });

    QUnit.test("Trash existing order", async function (assert) {
        assert.expect(5);

        let userInfos = {
            ...lunchInfos,
            lines: [
                {
                    id: 1,
                    product: [1, "Big Plate", "4.95"],
                    toppings: [],
                    quantity: 1,
                    price: 4.95,
                    raw_state: "new",
                    state: "To Order",
                    note: false
                }
            ],
            raw_state: "new",
            total: "4.95",
            paid_subtotal: "0",
            unpaid_subtotal: "4.95",
        };
        await makeLunchView({
            mockRPC: (route, args) => {
                if (route == '/lunch/user_location_get') {
                    return Promise.resolve(userInfos.user_location[0]);
                } else if (route == '/lunch/infos') {
                    return Promise.resolve(userInfos);
                } else if (route == '/lunch/trash') {
                    userInfos = {
                        ...userInfos,
                        lines: [],
                        raw_state: false,
                        total: 0,
                    };
                    return Promise.resolve(true);
                }
            }
        });

        assert.containsN(target, 'div.o_lunch_banner > .row > div', 3);
        assert.containsOnce(target, 'div.o_lunch_banner > .row > div:nth-child(2) button.fa-trash', 'should have trash icon');
        assert.containsOnce(target, 'div.o_lunch_banner > .row > div:nth-child(2) ul > li', 'should have one order line');

        assert.containsOnce(target, 'div.o_lunch_banner > .row > div:nth-child(3) button:contains(Order Now)');

        click(target, 'div.o_lunch_banner > .row > div:nth-child(2) button.fa-trash');
        await nextTick();
        assert.containsN(target, 'div.o_lunch_banner > .row > div', 1);
    });

    QUnit.test("Change existing order", async function (assert) {
        assert.expect(1);

        let userInfos = {
            ...lunchInfos,
            lines: [
                {
                    id: 1,
                    product: [1, "Big Plate", "4.95"],
                    toppings: [],
                    quantity: 1,
                    price: 4.95,
                    raw_state: "new",
                    state: "To Order",
                    note: false
                }
            ],
            raw_state: "new",
            total: "4.95",
            paid_subtotal: "0",
            unpaid_subtotal: "4.95",
        };
        await makeLunchView({
            mockRPC: (route, args) => {
                if (route == '/lunch/user_location_get') {
                    return Promise.resolve(userInfos.user_location[0]);
                } else if (route == '/lunch/infos') {
                    return Promise.resolve(userInfos);
                } else if (route == '/web/dataset/call_kw/lunch.order/update_quantity') {
                    assert.equal(args.args[1], 1, 'should increment order quantity by 1');
                    userInfos = {
                        ...userInfos,
                        lines: [
                            {
                                ...userInfos.lines[0],
                                product: [1, "Big Plate", "9.9"],
                                quantity: 2,
                                price: 4.95 * 2,
                            }
                        ],
                        total: 4.95 * 2,
                        unpaid_subtotal: 4.95 * 2,
                    };

                    return Promise.resolve(true);
                }
            }
        });

        click(target, 'div.o_lunch_banner > .row > div:nth-child(2) button.fa-plus-circle');
    });

    QUnit.test("Confirm existing order", async function (assert) {
        assert.expect(3);

        let userInfos = {
            ...lunchInfos,
            lines: [
                {
                    id: 1,
                    product: [1, "Big Plate", "4.95"],
                    toppings: [],
                    quantity: 1,
                    price: 4.95,
                    raw_state: "new",
                    state: "To Order",
                    note: false
                }
            ],
            raw_state: "new",
            total: "4.95",
            paid_subtotal: "0",
            unpaid_subtotal: "4.95",
        };
        await makeLunchView({
            mockRPC: (route, args) => {
                if (route == '/lunch/user_location_get') {
                    return Promise.resolve(userInfos.user_location[0]);
                } else if (route == '/lunch/infos') {
                    return Promise.resolve(userInfos);
                } else if (route == '/lunch/pay') {
                    assert.equal(args.user_id, false); // Should confirm order of current user
                    userInfos = {
                        ...userInfos,
                        lines: [
                            {
                                ...userInfos.lines[0],
                                raw_state: 'ordered',
                                state: 'Ordered,'
                            }
                        ],
                        raw_state: 'ordered',
                        wallet: userInfos.wallet - 4.95,
                    };
                    return Promise.resolve(true);
                }
            }
        });

        const wallet = target.querySelector('.o_lunch_banner .col-9 > .d-flex > span:nth-child(2)');
        assert.equal(wallet.innerText, '12.05€');

        click(target, 'div.o_lunch_banner > .row > div:nth-child(3) button');

        await nextTick();
        assert.equal(wallet.innerText, '7.10€', 'Wallet should update');
    });
});
});
