import { describe, expect, test } from "@odoo/hoot";
import { load } from "@odoo/o-spreadsheet";
import { defineSpreadsheetActions, defineSpreadsheetModels } from "../helpers/data";

defineSpreadsheetModels();
defineSpreadsheetActions();

describe.current.tags("headless");

test("Odoo formulas are migrated", () => {
    const data = {
        version: 16,
        sheets: [
            {
                cells: {
                    A1: { content: `=PIVOT("1")` },
                    A2: { content: `=PIVOT.HEADER("1")` },
                    A3: { content: `=FILTER.VALUE("1")` },
                    A4: { content: `=LIST("1")` },
                    A5: { content: `=LIST.HEADER("1")` },
                    A6: { content: `=PIVOT.POSITION("1")` },
                    A7: { content: `=pivot("1")` },
                },
            },
        ],
    };
    const migratedData = load(data);
    expect(migratedData.sheets[0].cells.A1).toBe(`=PIVOT.VALUE("1")`);
    expect(migratedData.sheets[0].cells.A2).toBe(`=PIVOT.HEADER("1")`);
    expect(migratedData.sheets[0].cells.A3).toBe(`=ODOO.FILTER.VALUE.V18("1")`);
    expect(migratedData.sheets[0].cells.A4).toBe(`=ODOO.LIST("1")`);
    expect(migratedData.sheets[0].cells.A5).toBe(`=ODOO.LIST.HEADER("1")`);
    expect(migratedData.sheets[0].cells.A6).toBe(`=ODOO.PIVOT.POSITION("1")`);
    expect(migratedData.sheets[0].cells.A7).toBe(`=PIVOT.VALUE("1")`);
});

test("Pivot 'day' arguments are migrated", () => {
    const data = {
        version: 16,
        odooVersion: 1,
        sheets: [
            {
                cells: {
                    A1: { content: `=ODOO.PIVOT("1","21/07/2022")` },
                    A2: { content: `=ODOO.PIVOT.HEADER("1","11/12/2022")` },
                    A3: { content: `=odoo.pivot("1","21/07/2021")` },
                    A4: { content: `=ODOO.PIVOT("1","test")` },
                    A5: { content: `=odoo.pivot("1","21/07/2021")+"21/07/2021"` },
                    A6: { content: `=BAD_FORMULA(` },
                },
            },
        ],
    };
    const migratedData = load(data);
    expect(migratedData.sheets[0].cells.A1).toBe(`=PIVOT.VALUE("1","07/21/2022")`);
    expect(migratedData.sheets[0].cells.A2).toBe(`=PIVOT.HEADER("1","12/11/2022")`);
    expect(migratedData.sheets[0].cells.A3).toBe(`=PIVOT.VALUE("1","07/21/2021")`);
    expect(migratedData.sheets[0].cells.A4).toBe(`=PIVOT.VALUE("1","test")`);
    expect(migratedData.sheets[0].cells.A5).toBe(`=PIVOT.VALUE("1","07/21/2021")+"21/07/2021"`);
    expect(migratedData.sheets[0].cells.A6).toBe(`=BAD_FORMULA(`);
});

test("Global filters: pivot fields is correctly added", () => {
    const data = {
        version: 16,
        globalFilters: [
            {
                id: "Filter1",
                type: "relation",
                label: "Relation Filter",
                fields: {
                    1: {
                        field: "foo",
                        type: "char",
                    },
                },
            },
        ],
        pivots: {
            1: {
                name: "test",
                measures: [],
                colGroupBys: [],
                rowGroupBys: [],
            },
        },
    };
    const migratedData = load(data);
    const filter = migratedData.globalFilters[0];
    const pivot = migratedData.pivots["1"];
    expect(pivot.fieldMatching).toEqual({
        Filter1: {
            chain: "foo",
            type: "char",
        },
    });
    expect(filter.fields).toBe(undefined);
});

test("Global filters: date is correctly migrated", () => {
    const data = {
        version: 16,
        globalFilters: [
            {
                id: "1",
                type: "date",
                rangeType: "year",
                defaultValue: { year: "last_year" },
            },
            {
                id: "2",
                type: "date",
                rangeType: "year",
                defaultValue: { year: "antepenultimate_year" },
            },
            {
                id: "3",
                type: "date",
                rangeType: "year",
                defaultValue: { year: "this_year" },
            },
        ],
    };
    const migratedData = load(data);
    const [f1, f2, f3] = migratedData.globalFilters;
    expect(f1.defaultValue).toBe(undefined);
    expect(f2.defaultValue).toBe(undefined);
    expect(f3.defaultValue).toBe(undefined);
});

test("List name default is model name", () => {
    const data = {
        version: 16,
        lists: {
            1: {
                name: "Name",
                model: "Model",
            },
            2: {
                model: "Model",
            },
        },
    };
    const migratedData = load(data);
    expect(Object.values(migratedData.lists).length).toBe(2);
    expect(migratedData.lists["1"].name).toBe("Name");
    expect(migratedData.lists["2"].name).toBe("Model");
});

test("Pivot name default is model name", () => {
    const data = {
        version: 16,
        pivots: {
            1: {
                name: "Name",
                model: "Model",
                measures: [],
                colGroupBys: [],
                rowGroupBys: [],
            },
            2: {
                model: "Model",
                measures: [],
                colGroupBys: [],
                rowGroupBys: [],
            },
        },
    };
    const migratedData = load(data);
    expect(Object.values(migratedData.pivots).length).toBe(2);
    expect(migratedData.pivots["1"].name).toBe("Name");
    expect(migratedData.pivots["2"].name).toBe("Model");
});

test("fieldMatchings are moved from filters to their respective datasources", () => {
    const data = {
        version: 16,
        globalFilters: [
            {
                id: "Filter",
                label: "MyFilter1",
                type: "relation",
                listFields: {
                    1: {
                        field: "parent_id",
                        type: "many2one",
                    },
                },
                pivotFields: {
                    1: {
                        field: "parent_id",
                        type: "many2one",
                    },
                },
                graphFields: {
                    fig1: {
                        field: "parent_id",
                        type: "many2one",
                    },
                },
            },
        ],
        pivots: {
            1: {
                name: "Name",
                measures: [],
                colGroupBys: [],
                rowGroupBys: [],
            },
        },
        lists: {
            1: {
                name: "Name",
            },
        },
        sheets: [
            {
                figures: [
                    {
                        id: "fig1",
                        tag: "chart",
                        data: {
                            type: "odoo_bar",
                            metaData: {},
                        },
                    },
                ],
            },
        ],
    };
    const migratedData = load(data);
    expect(migratedData.pivots["1"].fieldMatching).toEqual({
        Filter: { chain: "parent_id", type: "many2one" },
    });
    expect(migratedData.lists["1"].fieldMatching).toEqual({
        Filter: { chain: "parent_id", type: "many2one" },
    });
    expect(migratedData.sheets[0].figures[0].data.fieldMatching).toEqual({
        Filter: { chain: "parent_id", type: "many2one" },
    });
});

test("fieldMatchings offsets are correctly preserved after migration", () => {
    const data = {
        version: 16,
        globalFilters: [
            {
                id: "Filter",
                label: "MyFilter1",
                type: "relation",
                listFields: {
                    1: {
                        field: "parent_id",
                        type: "date",
                        offset: "-1",
                    },
                },
                pivotFields: {
                    1: {
                        field: "parent_id",
                        type: "date",
                        offset: "-1",
                    },
                },
                graphFields: {
                    fig1: {
                        field: "parent_id",
                        type: "date",
                        offset: "-1",
                    },
                },
            },
        ],
        pivots: {
            1: {
                name: "Name",
                measures: [],
                colGroupBys: [],
                rowGroupBys: [],
            },
        },
        lists: {
            1: {
                name: "Name",
            },
        },
        sheets: [
            {
                figures: [
                    {
                        id: "fig1",
                        tag: "chart",
                        data: {
                            type: "odoo_bar",
                            metaData: {},
                        },
                    },
                ],
            },
        ],
    };
    const migratedData = load(data);
    expect(migratedData.pivots["1"].fieldMatching).toEqual({
        Filter: { chain: "parent_id", type: "date", offset: "-1" },
    });
    expect(migratedData.lists["1"].fieldMatching).toEqual({
        Filter: { chain: "parent_id", type: "date", offset: "-1" },
    });
    expect(migratedData.sheets[0].figures[0].data.fieldMatching).toEqual({
        Filter: { chain: "parent_id", type: "date", offset: "-1" },
    });
});

test("group year/quarter/month filters to a single filter type", () => {
    const data = {
        version: 14,
        odooVersion: 5,
        globalFilters: [
            {
                id: "1",
                type: "relation",
                label: "a relational filter",
                defaultValue: [2],
                defaultValueDisplayNames: ["Mitchell Admin"],
                modelName: "res.users",
            },
            {
                id: "2",
                type: "date",
                label: "a year relational filter",
                rangeType: "year",
                defaultsToCurrentPeriod: true,
            },
            {
                id: "3",
                type: "date",
                label: "a quarter relational filter",
                rangeType: "quarter",
                defaultsToCurrentPeriod: true,
            },
            {
                id: "4",
                type: "date",
                label: "a month relational filter",
                rangeType: "month",
                defaultsToCurrentPeriod: true,
            },
            {
                id: "5",
                type: "date",
                label: "a relative date filter",
                defaultValue: "last_week",
                rangeType: "relative",
                defaultsToCurrentPeriod: false,
            },
        ],
    };
    const migratedData = load(data);
    const filters = migratedData.globalFilters;
    expect(filters).toEqual([
        {
            id: "1",
            type: "relation",
            label: "a relational filter",
            defaultValue: { operator: "in", ids: [2] },
            defaultValueDisplayNames: ["Mitchell Admin"],
            modelName: "res.users",
        },
        {
            id: "2",
            type: "date",
            label: "a year relational filter",
            defaultValue: "this_year",
        },
        {
            id: "3",
            type: "date",
            label: "a quarter relational filter",
            defaultValue: "this_quarter",
        },
        {
            id: "4",
            type: "date",
            label: "a month relational filter",
            defaultValue: "this_month",
        },
        {
            id: "5",
            type: "date",
            label: "a relative date filter",
            defaultValue: "last_7_days",
        },
    ]);
});

test("Pivot are migrated from 6 to 9", () => {
    const data = {
        version: 16,
        pivots: {
            1: {
                name: "Name",
                model: "Model",
                measures: [],
                colGroupBys: [],
                rowGroupBys: [],
                fieldMatching: { 1: { chain: "foo", type: "char" } },
            },
        },
    };
    const migratedData = load(data);
    expect(Object.values(migratedData.pivots).length).toBe(1);
    expect(migratedData.pivots["1"]).toEqual({
        type: "ODOO",
        fieldMatching: { 1: { chain: "foo", type: "char" } },
        name: "Name",
        model: "Model",
        measures: [],
        columns: [],
        rows: [],
        formulaId: "1",
    });
});

test("Pivot are migrated from 9 to 10", () => {
    const data = {
        version: 16,
        odooVersion: 9,
        pivots: {
            1: {
                type: "ODOO",
                name: "Name",
                model: "res.model",
                measures: ["probability"],
                colGroupBys: ["foo"],
                rowGroupBys: ["create_date:month"],
                formulaId: "1",
            },
        },
    };
    const migratedData = load(data);
    expect(Object.values(migratedData.pivots).length).toBe(1);
    expect(migratedData.pivots["1"]).toEqual({
        type: "ODOO",
        name: "Name",
        model: "res.model",
        measures: [{ id: "probability", fieldName: "probability", aggregator: undefined }],
        columns: [{ fieldName: "foo", granularity: undefined, order: undefined }],
        rows: [{ fieldName: "create_date", granularity: "month", order: undefined }],
        formulaId: "1",
    });
});

test("Pivot formulas are migrated from 9 to 10", () => {
    const data = {
        version: 16,
        odooVersion: 9,
        sheets: [
            {
                cells: {
                    A1: { content: `=ODOO.PIVOT("1")` },
                    A2: { content: `=ODOO.PIVOT.HEADER("1")` },
                    A3: { content: `=ODOO.PIVOT.POSITION("1")` },
                    A4: { content: `=ODOO.PIVOT.TABLE("1")` },
                    A5: { content: `=odoo.pivot("1")` },
                },
            },
        ],
    };
    const migratedData = load(data);
    expect(migratedData.sheets[0].cells.A1).toBe(`=PIVOT.VALUE("1")`);
    expect(migratedData.sheets[0].cells.A2).toBe(`=PIVOT.HEADER("1")`);
    expect(migratedData.sheets[0].cells.A3).toBe(`=ODOO.PIVOT.POSITION("1")`);
    expect(migratedData.sheets[0].cells.A4).toBe(`=PIVOT("1")`);
    expect(migratedData.sheets[0].cells.A5).toBe(`=PIVOT.VALUE("1")`);
});

test("Pivot formulas using pivot positions are migrated (11 to 12)", () => {
    const data = {
        version: 16,
        odooVersion: 9,
        sheets: [
            {
                cells: {
                    A1: {
                        content: `=-PIVOT.VALUE("1","balance","account_id",ODOO.PIVOT.POSITION("1","account_id",12),"date:quarter","4/"&ODOO.FILTER.VALUE("Year"))`,
                    },
                    A2: {
                        content: `=PIVOT.HEADER("1","account_id",ODOO.PIVOT.POSITION("1","account_id",14))`,
                    },
                    A3: { content: `=ODOO.PIVOT.POSITION("1","account_id",14)` },
                    A4: { content: `=ODOO.PIVOT.POSITION("1",14)` },
                },
            },
        ],
    };
    const migratedData = load(data);
    expect(migratedData.sheets[0].cells.A1).toBe(
        `=-PIVOT.VALUE("1","balance","#account_id",12,"date:quarter","4/"&ODOO.FILTER.VALUE.V18("Year"))`
    );
    expect(migratedData.sheets[0].cells.A2).toBe(`=PIVOT.HEADER("1","#account_id",14)`);
    expect(migratedData.sheets[0].cells.A3).toBe(`=ODOO.PIVOT.POSITION("1","account_id",14)`);
    expect(migratedData.sheets[0].cells.A4).toBe(`=ODOO.PIVOT.POSITION("1",14)`);
});

test("Pivot sorted columns are migrated (12 to 13)", () => {
    const data = {
        version: 23,
        odooVersion: 12,
        sheets: [],
        pivots: {
            1: {
                name: "test",
                sortedColumn: { groupId: [[], []], measure: "testMeasure", order: "desc" },
                columns: [],
                rows: [],
                measures: [{ id: "testMeasure:sum", fieldName: "testMeasure", aggregator: "sum" }],
            },
            2: {
                name: "test2",
                sortedColumn: { groupId: [[], [1]], measure: "testMeasure", order: "desc" },
                columns: [{ fieldName: "product_id" }],
                rows: [],
                measures: [{ id: "testMeasure:sum", fieldName: "testMeasure", aggregator: "sum" }],
            },
            3: {
                name: "test",
                // sortedColumn is not in the measures
                sortedColumn: { groupId: [[], []], measure: "testMeasure", order: "desc" },
                columns: [],
                rows: [],
                measures: [],
            },
        },
    };
    const migratedData = load(data);
    expect(migratedData.pivots["1"].sortedColumn).toEqual({
        domain: [],
        measure: "testMeasure:sum",
        order: "desc",
    });
    expect(migratedData.pivots["2"].sortedColumn).toBe(undefined);
    expect(migratedData.pivots["3"].sortedColumn).toBe(undefined);
});

test("Chart cumulatedStart is set to true if cumulative at migration", () => {
    const data = {
        version: 18.0,
        odooVersion: 9,
        sheets: [
            {
                figures: [
                    {
                        id: "fig1",
                        tag: "chart",
                        data: {
                            type: "odoo_bar",
                            metaData: {
                                cumulatedStart: undefined,
                                cumulative: true,
                            },
                            cumulative: true,
                        },
                    },
                    {
                        id: "fig2",
                        tag: "chart",
                        data: {
                            type: "odoo_bar",
                            metaData: {
                                cumulative: false,
                            },
                            cumulative: false,
                        },
                    },
                    {
                        id: "fig3",
                        tag: "chart",
                        data: {
                            type: "odoo_bar",
                            metaData: {
                                cumulative: true,
                                cumulatedStart: false,
                            },
                            cumulative: true,
                            cumulatedStart: false,
                        },
                    },
                ],
            },
        ],
    };
    const migratedData = load(data);
    const sheet = migratedData.sheets[0];
    expect(sheet.figures[0].data.metaData.cumulatedStart).toBe(true);
    expect(sheet.figures[0].data.cumulatedStart).toBe(true);
    expect(sheet.figures[1].data.metaData.cumulatedStart).toBe(false);
    expect(sheet.figures[1].data.cumulatedStart).toBe(false);
    expect(sheet.figures[2].data.metaData.cumulatedStart).toBe(false);
    expect(sheet.figures[2].data.cumulatedStart).toBe(false);
});

test("text global filter default value is now an array of strings", () => {
    const data = {
        version: "18.3.0",
        globalFilters: [
            {
                id: "1",
                type: "text",
                defaultValue: "foo",
                rangeOfAllowedValues: "Sheet1!A1:A2",
            },
            {
                id: "2",
                type: "text",
            },
            {
                id: "3",
                type: "text",
                defaultValue: "",
            },
        ],
    };
    const migratedData = load(data);
    expect(migratedData.globalFilters[0].defaultValue).toEqual({
        operator: "ilike",
        strings: ["foo"],
    });
    expect(migratedData.globalFilters[0].rangeOfAllowedValues).toBe(undefined);
    expect(migratedData.globalFilters[0].rangesOfAllowedValues).toEqual(["Sheet1!A1:A2"]);
    expect(migratedData.globalFilters[1].defaultValue).toBe(undefined);
    expect(migratedData.globalFilters[1].rangeOfAllowedValues).toBe(undefined);
    expect(migratedData.globalFilters[1].rangesOfAllowedValues).toBe(undefined);
    expect(migratedData.globalFilters[2].defaultValue).toBe(undefined);
});

test("global filter default value have operators", () => {
    const data = {
        version: "18.4.14",
        globalFilters: [
            {
                id: "1",
                type: "text",
                defaultValue: ["foo"],
            },
            {
                id: "2",
                type: "relation",
                modelName: "res.partner",
                defaultValue: [1],
            },
            {
                id: "3",
                type: "relation",
                modelName: "res.company",
                defaultValue: [2],
                includeChildren: true,
            },
            {
                id: "4",
                type: "boolean",
                defaultValue: [true],
            },
            {
                id: "5",
                type: "boolean",
                defaultValue: [false],
            },
            {
                id: "6",
                type: "boolean",
                defaultValue: [true, false],
            },
        ],
    };
    const migratedData = load(data);
    expect(migratedData.globalFilters[0].defaultValue).toEqual({
        operator: "ilike",
        strings: ["foo"],
    });
    expect(migratedData.globalFilters[1].defaultValue).toEqual({
        operator: "in",
        ids: [1],
    });
    expect(migratedData.globalFilters[2].defaultValue).toEqual({
        operator: "child_of",
        ids: [2],
    });
    expect(migratedData.globalFilters[3].defaultValue).toEqual({ operator: "set" });
    expect(migratedData.globalFilters[4].defaultValue).toEqual({ operator: "not set" });
    expect(migratedData.globalFilters[5].defaultValue).toBe(undefined);
});

test("Date with antepenultimate_year is not supported anymore", () => {
    const data = {
        version: "1",
        globalFilters: [
            {
                id: "1",
                type: "date",
                defaultValue: { year: "antepenultimate_year" },
                rangeType: "fixedPeriod",
            },
        ],
    };
    const migratedData = load(data);
    expect(migratedData.globalFilters[0].defaultValue).toBe(undefined);
});

test("Default value is now undefined", () => {
    const data = {
        version: "1",
        globalFilters: [
            {
                id: "1",
                type: "relation",
                label: "a relation filter",
                defaultValue: [],
            },
        ],
    };
    const migratedData = load(data);
    expect(migratedData.globalFilters[0].defaultValue).toBe(undefined);
});

test("period values are correctly renamed/removed", () => {
    const data = {
        version: 14,
        odooVersion: 5,
        globalFilters: [
            {
                id: "1",
                type: "date",
                label: "My label",
                rangeType: "relative",
                defaultValue: "last_six_month",
            },
            {
                id: "2",
                type: "date",
                label: "My label",
                rangeType: "relative",
                defaultValue: "last_three_years",
            },
            {
                id: "3",
                type: "date",
                label: "My label",
                rangeType: "relative",
                defaultValue: "last_month",
            },
            {
                id: "4",
                type: "date",
                label: "My label",
                rangeType: "relative",
                defaultValue: "last_week",
            },
            {
                id: "5",
                type: "date",
                label: "My label",
                rangeType: "relative",
                defaultValue: "last_three_months",
            },
            {
                id: "6",
                type: "date",
                label: "My label",
                rangeType: "relative",
                defaultValue: "last_year",
            },
        ],
    };
    const migratedData = load(data);
    const filters = migratedData.globalFilters;
    expect(filters[0].defaultValue).toBe(undefined);
    expect(filters[1].defaultValue).toBe(undefined);
    expect(filters[2].defaultValue).toBe("last_30_days");
    expect(filters[3].defaultValue).toBe("last_7_days");
    expect(filters[4].defaultValue).toBe("last_90_days");
    expect(filters[5].defaultValue).toBe("last_12_months");
});

test("Date filters are migrated", () => {
    const data = {
        version: 14,
        odooVersion: 5,
        globalFilters: [
            {
                id: "1",
                type: "date",
                label: "Fixed Period",
                rangeType: "fixedPeriod",
                disabledPeriods: ["quarter"],
            },
            {
                id: "2",
                type: "date",
                label: "Relative",
                rangeType: "relative",
            },
            {
                id: "3",
                type: "date",
                label: "From/to",
                rangeType: "fromTo",
            },
        ],
    };
    const migratedData = load(data);
    const filters = migratedData.globalFilters;
    expect(filters[0].rangeType).toBe(undefined);
    expect(filters[1].rangeType).toBe(undefined);
    expect(filters[2].rangeType).toBe(undefined);

    expect(filters[0].disabledPeriods).toBe(undefined);
});

test("18.5.10: ODOO.FILTER.VALUE to ODOO.FILTER.VALUE.V18 in cells", () => {
    const data = {
        version: "18.4.14",
        sheets: [
            {
                cells: {
                    A1: '=ODOO.FILTER.VALUE("MyFilter")+odoo.filter.value("AnotherFilter")',
                },
            },
        ],
    };
    const migratedData = load(data);
    expect(migratedData.sheets[0].cells.A1).toBe(
        `=ODOO.FILTER.VALUE.V18("MyFilter")+ODOO.FILTER.VALUE.V18("AnotherFilter")`
    );
});
