import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
import { mainPage } from "../../support/page_objects/mainPage";
import { loginPage } from "../../support/page_objects/navigation";

// locally configured hook (server.js)
let hookPath = "http://localhost:9090/hook";

function createWebhook(hook, test) {
    cy.get('.nc-actions-menu-btn').should('exist').click();
    cy.getActiveMenu().find('.ant-dropdown-menu-title-content').contains('Webhooks').click()

    // cy.get(".nc-btn-webhook").should("exist").click();
    cy.get(".nc-btn-create-webhook").should("exist").click();

    // hardcode "Content-type: application/json"
    cy.get(".ant-tabs-tab-btn").contains("Headers").should("exist").click();

    // kludge : as neither scrollIntoView nor scrollTo didn't yield any results
    // cy.getActiveSelection().find('.ant-select-item').contains('Content-Type).scrollIntoView();
    // cy.getActiveSelection().find('.rc-virtual-list').scrollTo('center');
    // cy.getActiveSelection().select('Content-Type', { force: true });

    cy.get(".nc-input-hook-header-key")
      .should("exist")
      .click()
      .type('{downarrow}')
      .type('{downarrow}')
      .type('{downarrow}')
      .type('{downarrow}')
      .type('{downarrow}')
      .type('{downarrow}')
      .type('{downarrow}')
      .type('{downarrow}')
      .type('{downarrow}')
      .type('{downarrow}')
      .type('{downarrow}')
      .type('{downarrow}')

    cy.getActiveSelection().find('.ant-select-item-option-content').contains('Content-Type').should('exist').click();

    cy.get("input.nc-input-hook-header-value")
        .should("exist")
        .clear({ force: true })
        .type("application/json", { force: true });

    cy.get('.nc-hook-header-tab-checkbox').find('input.ant-checkbox-input').should('exist').click();

    // common routine for both create & modify to configure hook
    configureWebhook(hook, test);
}

function deleteWebhook(index) {
    cy.get('.nc-actions-menu-btn').should('exist').click();
    cy.getActiveMenu().find('.ant-dropdown-menu-title-content').contains('Webhooks').click()

    cy.get(".nc-hook-delete-icon").eq(index).click({ force: true });
    cy.toastWait("Hook deleted successfully");
    cy.get("body").type("{esc}");
}

function openWebhook(index) {
    cy.get('.nc-actions-menu-btn').should('exist').click();
    cy.getActiveMenu().find('.ant-dropdown-menu-title-content').contains('Webhooks').click()

    cy.get(".nc-hook").eq(index).click({ force: true });
}

function configureWebhook(hook, test) {
    // configure what ever is present. ignore rest
    // currently works for only URL type

    if (hook?.title) {
        cy.get(".nc-text-field-hook-title")
            .should("exist")
            .clear()
            .type(hook.title);
    }

    if (hook?.event) {
        cy.get(".nc-text-field-hook-event").should("exist").click();
        cy.getActiveSelection()
            .find(`.ant-select-item`)
            .contains(hook.event)
            .should("exist")
            .click();
    }

    if (hook?.url?.path) {
        cy.get(".nc-text-field-hook-url-path")
            .should("exist")
            .clear()
            .type(hook.url.path);
    }

    if (hook?.deleteCondition === true) {
        cy.get(".nc-filter-item-remove-btn")
            .should("exist")
            .click({ force: true });
    }

    if (hook?.condition) {
        cy.get(".nc-check-box-hook-condition").should("exist").click();
        cy.get(".menu-filter-dropdown")
            .last()
            .find("button")
            .contains("Add Filter")
            .click();

        cy.get(".nc-filter-field-select")
            .should("exist")
            .last()
            .click()
        cy.get('.ant-select-dropdown:visible')
            .should('exist')
            .find(`.ant-select-item`)
            .contains(new RegExp("^" + hook.condition.column + "$", "g"))
            .should('exist')
            .click();
        cy.wait(1000);

        cy.get(".nc-filter-operation-select").should("exist").last().click();
        cy.get('.ant-select-dropdown:visible')
            .should('exist')
            .find(`.ant-select-item`)
            .contains(hook.condition.operator)
            .should('exist')
            .click();
        if (hook.condition.operator != "is null" && hook.condition.operator != "is not null") {
            cy.get(".nc-filter-value-select")
              .should("exist")
              .last()
              .type(hook.condition.value);
            cy.get(".nc-filter-operation-select").last().click();
        }
    }

    if (test) {
        cy.get(".nc-btn-webhook-test").should("exist").click();
        cy.toastWait("Webhook tested successfully");
    }

    cy.get(".nc-btn-webhook-save").should("exist").click();
    cy.toastWait("Webhook details updated successfully");
    cy.get(".nc-icon-hook-navigate-left").should("exist").click();
    cy.get("body").type("{esc}");
}

function clearServerData() {
    // clear stored data in server
    cy.request("http://localhost:9090/hook/clear");

    // ensure stored message count is 0
    cy.request("http://localhost:9090/hook/count").then((msg) => {
        cy.log(msg.body);
        expect(msg.body).to.equal(0);
    });
}

function addNewRow(index, cellValue) {
    cy.get(".nc-add-new-row-btn:visible").should("exist");
    cy.get(".nc-add-new-row-btn").click();
    cy.wait(1000);
    cy.get(".nc-expand-col-Title").find(".nc-cell > input").first().type(cellValue);
    cy.getActiveDrawer()
        .find(".ant-btn-primary")
        .click();

    cy.toastWait("updated successfully");
    cy.getActiveDrawer()
      .find(".ant-btn")
      .contains("Cancel")
      .click();
    mainPage.getCell("Title", index).contains(cellValue).should("exist");
}

function updateRow(index, cellValue) {
    cy.get(".nc-row-expand")
      .eq(index-1)
      .click({ force: true });

    cy.get(".nc-expand-col-Title").find(".nc-cell > input")
      .should("exist")
      .first()
      .clear()
      .type(cellValue);

    cy.getActiveDrawer()
      .find("button")
      .contains("Save row")
      .click({ force: true });

    // partial toast message
    cy.toastWait("updated successfully");
    cy.getActiveDrawer()
        .find("button")
        .contains("Cancel")
        .click({ force: true });
}

function verifyHookTrigger(count, lastValue) {
    cy.request("http://localhost:9090/hook/count").then((msg) => {
        cy.log(msg.body);
        expect(msg.body).to.equal(count);
    });
    if (count) {
        cy.request("http://localhost:9090/hook/last").then((msg) => {
            cy.log(msg.body);
            expect(msg.body.Title).to.equal(lastValue);
        });
    }
}

function deleteRow(index) {
    mainPage
      .getCell("Title", index)
      .rightclick();

    // delete row
    cy.getActiveMenu()
      .find('.ant-dropdown-menu-item:contains("Delete Row")')
      .first()
      .click({ force: true });
}

export const genTest = (apiType, dbType) => {
    if (!isTestSuiteActive(apiType, dbType)) return;
    describe(`Webhook`, () => {
        before(() => {
            loginPage.loginAndOpenProject(apiType, dbType);
            cy.createTable("Temp");
            cy.wait(1000);

            cy.saveLocalStorage();
        });

        beforeEach(() => {
            cy.restoreLocalStorage();
            cy.wait(1000);
        });

        after(() => {
            cy.deleteTable("Temp");
            cy.saveLocalStorage();
            cy.wait(1000);
        });

        it("Create: 'After Insert' event", () => {
            createWebhook({
                title: "hook-1",
                event: "After Insert",
                type: "URL",
                url: {
                    method: "POST",
                    path: hookPath,
                },
            });
            clearServerData();
            addNewRow(1, "Poole");
            verifyHookTrigger(1, "Poole");
            updateRow(1, "Delaware");
            verifyHookTrigger(1, "Poole");
            deleteRow(1);
            verifyHookTrigger(1, "Poole");
        });

        it("Add 'After Update' event", () => {
            createWebhook({
                title: "hook-2",
                event: "After Update",
                type: "URL",
                url: {
                    method: "POST",
                    path: hookPath,
                },
            });
            clearServerData();
            addNewRow(1, "Poole");
            verifyHookTrigger(1, "Poole");
            updateRow(1, "Delaware");
            verifyHookTrigger(2, "Delaware");
            deleteRow(1);
            verifyHookTrigger(2, "Delaware");
        });

        it("Add 'After Delete' event", () => {
            createWebhook({
                title: "hook-3",
                event: "After Delete",
                type: "URL",
                url: {
                    method: "POST",
                    path: hookPath,
                },
            });
            clearServerData();
            addNewRow(1, "Poole");
            verifyHookTrigger(1, "Poole");
            updateRow(1, "Delaware");
            verifyHookTrigger(2, "Delaware");
            deleteRow(1);
            verifyHookTrigger(3, "Delaware");
        });

        it("Modify webhook", () => {
            openWebhook(0);
            configureWebhook({ event: "After Delete" });
            openWebhook(1);
            configureWebhook({ event: "After Delete" });

            clearServerData();
            addNewRow(1, "Poole");
            verifyHookTrigger(0, "");
            updateRow(1, "Delaware");
            verifyHookTrigger(0, "");
            deleteRow(1);
            verifyHookTrigger(3, "Delaware");
        });

        it("Delete webhook", () => {
            deleteWebhook(2);
            deleteWebhook(1);
            deleteWebhook(0);

            clearServerData();
            addNewRow(1, "Poole");
            verifyHookTrigger(0, "");
            updateRow(1, "Delaware");
            verifyHookTrigger(0, "");
            deleteRow(1);
            verifyHookTrigger(0, "");
        });

        it("Create, with condition", () => {
            // create 3 webhooks with all three events, with condition this time
            createWebhook({
                title: "hook-with-condition-1",
                event: "After Insert",
                type: "URL",
                url: {
                    method: "POST",
                    path: hookPath,
                },
                condition: {
                    column: "Title",
                    operator: "is like",
                    value: "Poole",
                },
            });
            createWebhook({
                title: "hook-with-condition-2",
                event: "After Update",
                type: "URL",
                url: {
                    method: "POST",
                    path: hookPath,
                },
                condition: {
                    column: "Title",
                    operator: "is like",
                    value: "Poole",
                },
            });
            createWebhook({
                title: "hook-with-condition-3",
                event: "After Delete",
                type: "URL",
                url: {
                    method: "POST",
                    path: hookPath,
                },
                condition: {
                    column: "Title",
                    operator: "is like",
                    value: "Poole",
                },
            });

            clearServerData();
            addNewRow(1, "Poole");
            addNewRow(2, "Delaware");
            verifyHookTrigger(1, "Poole");
            updateRow(1, "Delaware");
            updateRow(2, "Poole");
            verifyHookTrigger(2, "Poole");
            deleteRow(2);
            deleteRow(1);
            verifyHookTrigger(3, "Poole");
        });

        it("Modify trigger condition", () => {
            openWebhook(0);
            configureWebhook({ deleteCondition: true });
            openWebhook(1);
            configureWebhook({ deleteCondition: true });
            openWebhook(2);
            configureWebhook({ deleteCondition: true });

            clearServerData();
            addNewRow(1, "Poole");
            addNewRow(2, "Delaware");
            verifyHookTrigger(2, "Delaware");
            updateRow(1, "Delaware");
            updateRow(2, "Poole");
            verifyHookTrigger(4, "Poole");
            deleteRow(2);
            deleteRow(1);
            verifyHookTrigger(6, "Delaware");
        });

        it("Delete trigger condition", () => {
            deleteWebhook(2);
            deleteWebhook(1);
            deleteWebhook(0);

            clearServerData();
            addNewRow(1, "Poole");
            verifyHookTrigger(0, "");
            updateRow(1, "Delaware");
            verifyHookTrigger(0, "");
            deleteRow(1);
            verifyHookTrigger(0, "");
        });
    });
};

/**
 * @copyright Copyright (c) 2021, Xgene Cloud Ltd
 *
 * @author Raju Udava <sivadstala@gmail.com>
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */
