/** @odoo-module **/

import {useEffect, useEnv, useSubEnv} from "@odoo/owl";
import {memoize} from "@web/core/utils/functions";
import {registry} from "@web/core/registry";

const translateRegistry = registry.category("translate");

const getAccessRights = memoize(async function getAccessRights(orm) {
    const rightsToCheck = {
        "ir.ui.view": "write",
        "ir.rule": "read",
        "ir.model.access": "read",
    };
    const proms = Object.entries(rightsToCheck).map(([model, operation]) => {
        return orm.call(model, "check_access_rights", [], {
            operation,
            raise_exception: false,
        });
    });
    const [canEditView, canSeeRecordRules, canSeeModelAccess] = await Promise.all(proms);
    const accessRights = {canEditView, canSeeRecordRules, canSeeModelAccess};
    return accessRights;
});

class TranslateContext {
    constructor(env, defaultCategories) {
        this.orm = env.services.orm;
        this.categories = new Map(defaultCategories.map((cat) => [cat, new Set()]));
    }

    activateCategory(category, context) {
        const contexts = this.categories.get(category) || new Set();
        contexts.add(context);
        this.categories.set(category, contexts);

        return () => {
            contexts.delete(context);
            if (contexts.size === 0) {
                this.categories.delete(category);
            }
        };
    }

    async getItems(env) {
        const accessRights = await getAccessRights(this.orm);
        return [...this.categories.entries()]
            .flatMap(([category, contexts]) => {
                return translateRegistry
                    .category(category)
                    .getAll()
                    .map((factory) => factory(Object.assign({env, accessRights}, ...contexts)));
            })
            .filter(Boolean)
            .sort((x, y) => {
                const xSeq = x.sequence || 1000;
                const ySeq = y.sequence || 1000;
                return xSeq - ySeq;
            });
    }
}

const translateContextSymbol = Symbol("translateContext");
export function createTranslateContext(env, {categories = []} = {}) {
    return {[translateContextSymbol]: new TranslateContext(env, categories)};
}

export function useOwnTranslateContext({categories = []} = {}) {
    useSubEnv(createTranslateContext(useEnv(), {categories}));
}

export function useEnvTranslateContext() {
    const translateContext = useEnv()[translateContextSymbol];
    if (!translateContext) {
        throw new Error("There is no translate context available in the current environment.");
    }
    return translateContext;
}

export function useTranslateCategory(category, context = {}) {
    const env = useEnv();
    if (env.translate) {
        const translateContext = useEnvTranslateContext();
        useEffect(
            () => translateContext.activateCategory(category, context),
            () => []
        );
    }
}
