# © 2021 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from datetime import datetime

from odoo.exceptions import AccessError

from odoo.addons.base_rest import restapi
from odoo.addons.component.core import Component


class OperationsService(Component):
    _inherit = "base.rest.service"
    _name = "operation.service"
    _usage = "operation"
    _collection = "acc.rest.api.services"
    _description = """
        Operation Services
        Accès aux opérations
    """

    @restapi.method(
        [(["/all"], "GET")],
        output_param=restapi.CerberusValidator("_validator_return_get_all"),
        cors="*",
        crsf=False,
    )
    def get_all(self):
        """
        Retourne la liste de toutes les opérations dans lesquelles l'utilisateur
        ou sa société sont engagés
        """
        # Get partners
        partner_id = self.env["res.users"].browse(self.request.uid).partner_id
        partner_ids = partner_id + partner_id.parent_id
        # Get operations
        operations_pmo = self.env["acc.operation"].search(
            [("pmo_id", "in", partner_ids.ids)]
        )
        operations_counter = (
            self.env["acc.counter"]
            .search([("partner_id", "in", partner_ids.ids)])
            .mapped("acc_operation_id")
        )
        operations = operations_pmo | operations_counter

        # Get news
        news = self.env["acc.actu"].search([("operation_id", "=", False)], limit=10)

        datas = {}
        if operations:
            # Return datas
            datas["operations"] = operations.mapped(
                lambda o: {
                    "id": o.id,
                    "name": o.name,
                    "description": o.description,
                    "date_start": o.date_start_contract
                    if o.date_start_contract
                    else None,
                    "date_end": o.date_end_contract if o.date_end_contract else None,
                    "distribution_key": o.distribution_key
                    if o.distribution_key
                    else None,
                    "pmo": o.sudo().pmo_id.name,
                    "image": o.image_256.decode("utf-8") if o.image_256 else None,
                }
            )
            datas["news"] = news.mapped(
                lambda n: {
                    "id": n.id,
                    "name": n.name,
                    "date_actu": n.date_actu if n.date_actu else None,
                    "content_html": n.content_html,
                }
            )
        return datas

    @restapi.method(
        [(["/<int:id>/home"], "GET")],
        output_param=restapi.CerberusValidator("_validator_return_get_id"),
        cors="*",
        crsf=False,
    )
    def get_id(self, _id):
        """
        Retourne les statistiques générales et les actualités liées à une opération
        dans laquelle l'utilisateur ou sa société sont engagés
        """
        operation = self.env["acc.operation"].browse(_id)

        role = self._get_role(operation)
        if not role.get("isIn"):
            return AccessError()

        power_install = sum(operation.sudo().acc_injection_ids.mapped("power_instal"))

        try:
            power_tot = operation.get_power_tot()
            cons_rate = round((power_tot[2] / power_tot[1]) * 100, 2)
            prod_rate = round((power_tot[2] / power_tot[0]) * 100, 2)
        except Exception:
            power_tot = (0, 0, 0, None)
            cons_rate = prod_rate = 0

        nb_conso = (
            self.env["acc.counter"]
            .sudo()
            .search_count(
                [
                    ("acc_operation_id", "=", operation.id),
                    ("is_delivery", "=", True),
                ]
            )
        )
        nb_prod = (
            self.env["acc.counter"]
            .sudo()
            .search_count(
                [
                    ("acc_operation_id", "=", operation.id),
                    ("is_injection", "=", True),
                ]
            )
        )

        datas = {
            "role": role,
            "id": operation.id,
            "name": operation.name,
            "description": operation.description,
            "date_start": operation.date_start_contract
            if operation.date_start_contract
            else None,
            "date_end": operation.date_end_contract
            if operation.date_end_contract
            else None,
            "distribution_key": operation.distribution_key
            if operation.distribution_key
            else None,
            "pmo": operation.sudo().pmo_id.name,
            "consumer_nb": nb_conso,
            "productor_nb": nb_prod,
            "power_install": power_install,
            "image": operation.image_256.decode("utf-8")
            if operation.image_256
            else None,
            "conso_tot": power_tot[0],
            "prod_tot": power_tot[1],
            "month": power_tot[3],
            "conso_rate": cons_rate,
            "prod_rate": prod_rate,
        }
        # Get news
        news = (
            self.env["acc.actu"].sudo().search([("operation_id", "=", _id)], limit=10)
        )
        if news:
            datas["news"] = news.mapped(
                lambda n: {
                    "id": n.id,
                    "name": n.name,
                    "date_actu": n.date_actu,
                    "content_html": n.content_html,
                }
            )

        return datas

    @restapi.method(
        [(["/<int:id>/document"], "POST")],
        input_param=restapi.CerberusValidator("_validator_get_doc"),
        output_param=restapi.CerberusValidator("_validator_return_get_doc"),
        cors="*",
        crsf=False,
    )
    def get_doc(self, _id, **params):
        """
        Retourne les documents (Factures) liés à une opération
        dans laquelle l'utilisateur ou sa société sont engagés
        """
        operation = self.env["acc.operation"].browse(_id)
        role = self._get_role(operation)
        base_url = self.env["ir.config_parameter"].sudo().get_param("web.base.url")

        if not role.get("isIn"):
            return AccessError()

        type = self.request.params.get("type", False)

        datas = {
            "role": role,
            "id": operation.id,
            "name": operation.name,
        }

        # Récupération de toutes les factures liées à l'opération spécifiée
        acc_account_ids = self.env["acc.account"].search(
            [("acc_operation_id", "=", _id), ("state", "=", "published")]
        )

        # Récupération de toutes les factures externes
        # liées à l'opération spécifiée
        domain = [("acc_operation_id", "=", _id)]
        domain += [
            ("type", "=", "facture"),
        ]
        acc_contract_ids_f = self.env["acc.contract"].search(domain)
        invoice_exist = False
        if acc_contract_ids_f or acc_account_ids:
            invoice_exist = True

        # Récupération de tous les contrats liés à l'opération spécifiée
        domain_c = [("acc_operation_id", "=", _id)]
        domain_pmo = [("acc_operation_id", "=", _id)]

        role = self._get_role(operation)
        if role.get("isConsumer") or role.get("isProductor"):
            domain_c += [
                "|",
                ("type", "=", "other"),
                ("type", "=", "vente_achat"),
            ]

        if role.get("isPmo"):
            domain_pmo += [("type", "!=", False)]
            acc_contract_ids = self.env["acc.contract"].search(domain_pmo)
        else:
            acc_contract_all = (
                self.env["acc.contract"]
                .sudo()
                .search([
                    ("acc_operation_id", "=", _id),
                    ("type", "=", "all"),
                    ])
                )
            acc_contract_ids = self.env["acc.contract"].search(domain_c)
            acc_contract_ids += acc_contract_all

        acc_contract_pmo = self.env["acc.contract"].search(
            [
                ("acc_operation_id", "=", _id),
                ("type", "=", "pmo"),
            ]
        )
        acc_contract_ids += acc_contract_pmo
        contract_exist = False
        if acc_contract_ids:
            contract_exist = True
        if type == "invoice" and invoice_exist:

            datas["documents"] = (
                acc_account_ids.sudo().mapped(
                    lambda n: {
                        "id": n.id,
                        "name": n.name,
                        "date": n.date,
                        "start_date": n.start_date,
                        "end_date": n.end_date,
                        "amount_total": n.amount_total,
                        "consumer": n.consumer_id.name,
                        "prm_c": n.acc_delivery_id.name,
                        "url": base_url + n.get_portal_url(report_type="pdf"),
                    }
                )
                if acc_account_ids
                else []
            )

            datas["factures_externes"] = (
                acc_contract_ids_f.sudo().mapped(
                    lambda n: {
                        "id": n.id,
                        "name": n.name,
                        "start_date": n.start_date,
                        "end_date": n.end_date,
                        "type": n.type,
                        "seller": n.seller_id.name,
                        "url": base_url + n.get_portal_url(),
                    }
                )
                if acc_contract_ids_f
                else []
            )
        elif type == "contract" or (not invoice_exist and contract_exist):

            datas["contracts"] = (
                acc_contract_ids.mapped(
                    lambda n: {
                        "id": n.id,
                        "name": n.name,
                        "start_date": n.start_date,
                        "end_date": n.end_date,
                        "type": n.type,
                        "url": base_url + n.get_portal_url(),
                    }
                )
                if acc_contract_ids
                else []
            )
            datas["contracts_pmo"] = (
                acc_contract_pmo.mapped(
                    lambda n: {
                        "id": n.id,
                        "name": n.name,
                        "start_date": n.start_date,
                        "end_date": n.end_date,
                        "type": n.type,
                        "url": base_url + n.get_portal_url(),
                    }
                )
                if acc_contract_pmo
                else []
            )
        datas["contract_exist"] = contract_exist
        datas["invoice_exist"] = invoice_exist
        return datas

    @restapi.method(
        [(["/<int:id>/pmo"], "POST")],
        input_param=restapi.CerberusValidator("_validator_get_pmo"),
        # output_param=restapi.CerberusValidator("_validator_get_return_pmo"),
        cors="*",
        crsf=False,
    )
    def get_pmo(self, _id, **params):
        """
        Retourne les courbes de production et de consommation liées à une opération
        dans laquelle l'utilisateur ou sa société ont le rôle de PMO
        """
        operation = self.env["acc.operation"].browse(_id)

        # Check rights
        role = self._get_role(operation)

        # Get params
        scale = params.get("scale", False)
        date_start = params.get("date_start", False)
        date_end = params.get("date_end", False)
        if operation.is_data_enedis:
            if scale:
                graph_data = operation.sudo().graph_view_global(scale=scale)
            elif date_start and date_end:
                graph_data = operation.sudo().graph_view_global(
                    date_start=datetime.strptime(date_start, "%Y-%m-%d"),
                    date_end=datetime.strptime(date_end, "%Y-%m-%d"),
                )
            else:
                graph_data = operation.sudo().graph_view_global(scale="week")
        else:
            graph_data = None

        datas = {"role": role, "graph_datas": graph_data}
        return datas

    @restapi.method(
        [(["/<int:id>/consumer"], "POST")],
        input_param=restapi.CerberusValidator("_validator_get_prm"),
        # output_param=restapi.CerberusValidator("_validator_get_return_consumer"),
        cors="*",
        crsf=False,
    )
    def get_consumer(self, _id, **params):
        """
        Retourne les courbes de consommation liées à une opération ou à un PRM
        dans laquelle l'utilisateur ou sa société ont le rôle de PMO
        """
        operation = self.env["acc.operation"].browse(_id).sudo()

        partner_id = self.env["res.users"].browse(self.request.uid).partner_id

        # Check rights
        role = self._get_role(operation)
        if not role.get("isConsumer") and not role.get("isPmo"):
            raise AccessError(
                "User id "
                + str(role.get("id"))
                + " does not have access to ("
                + role.get("name")
                + ") for Consumer role"
            )

        # Get params
        scale = params.get("scale", False)
        date_start = params.get("date_start", False)
        date_end = params.get("date_end", False)
        prm_id = params.get("prm_id", False)
        consumer_id = params.get("partner_id", False)

        domain_prm = [("acc_operation_id", "=", _id), ("is_delivery", "=", True)]

        if not role.get("isPmo"):
            domain_prm.append(
                ("partner_id", "in", [partner_id.id, partner_id.parent_id.id])
            )
        prm_ids = (
            self.env["acc.counter"].sudo().search(domain_prm, order="partner_id asc")
        )

        prm_name = prm_ids.mapped(
            lambda p: {
                "id": p.id,
                "name": p.name,
                "partner_id": p.partner_id.id,
                "street": p.street,
            }
        )
        consumer_name = prm_ids.mapped("partner_id").mapped(
            lambda p: {
                "id": p.id,
                "name": p.name,
            }
        )

        if role.get("isConsumer") and not role.get("isPmo") and not prm_id:
            consumer_id = consumer_name[0]["id"]
        if operation.is_data_enedis:
            if scale:
                graph_datas = operation.graph_view_type(
                    type="cons", scale=scale, prm_id=prm_id, partner_id=consumer_id
                )
            elif date_start and date_end:
                graph_datas = operation.graph_view_type(
                    type="cons",
                    date_start=datetime.strptime(date_start, "%Y-%m-%d"),
                    date_end=datetime.strptime(date_end, "%Y-%m-%d"),
                    prm_id=prm_id,
                    partner_id=consumer_id,
                )
            else:
                graph_datas = operation.graph_view_type(
                    type="cons", scale="week", prm_id=prm_id, partner_id=consumer_id
                )
            if prm_id:
                graph_datas["name"] = (
                    "PRM N° " + self.env["acc.counter"].sudo().browse(prm_id).name
                )
            if consumer_id:
                graph_datas["name"] = (
                    self.env["res.partner"].sudo().browse(consumer_id).name
                )
            graph_datas["prm_id"] = prm_id
            graph_datas["partner_id"] = consumer_id
        else:
            graph_datas = None

        datas = {
            "role": role,
            "graph_datas": graph_datas,
            "prms": prm_name,
            "consumers": consumer_name,
        }
        return datas

    @restapi.method(
        [(["/<int:id>/consumer-financial"], "POST")],
        input_param=restapi.CerberusValidator("_validator_get_prm"),
        cors="*",
        crsf=False,
    )
    def get_consumer_financial(self, _id, **params):
        """
        Retourne les données financières de consommation liées à une opération ou à un PRM
        dans laquelle l'utilisateur ou sa société ont le rôle de PMO
        """
        operation = self.env["acc.operation"].browse(_id).sudo()

        partner_id = self.env["res.users"].browse(self.request.uid).partner_id

        # Check rights
        role = self._get_role(operation)
        if not role.get("isConsumer") and not role.get("isPmo"):
            raise AccessError(
                "User id "
                + str(role.get("id"))
                + " does not have access to ("
                + role.get("name")
                + ") for Consumer role"
            )

        # Get params
        prm_id = params.get("prm_id", False)

        domain_prm = [("acc_operation_id", "=", _id), ("is_delivery", "=", True)]

        if not role.get("isPmo"):
            domain_prm.append(
                ("partner_id", "in", [partner_id.id, partner_id.parent_id.id])
            )
        prm_ids = self.env["acc.counter"].sudo().search(domain_prm)

        prm_name = prm_ids.mapped(
            lambda p: {
                "id": p.id,
                "name": p.name,
                "partner_id": p.partner_id.id,
                "street": p.street,
            }
        )

        if operation.is_data_enedis:
            graph_datas = operation.get_financial_monitoring(type="cons", prm_id=prm_id)
            if prm_id:
                graph_datas["name"] = (
                    "PRM N° " + self.env["acc.counter"].sudo().browse(prm_id).name
                )
            graph_datas["prm_id"] = prm_id
        else:
            graph_datas = None

        datas = {
            "graph_datas": graph_datas,
            "role": role,
            "prms": prm_name,
        }
        return datas

    @restapi.method(
        [(["/<int:id>/productor"], "POST")],
        input_param=restapi.CerberusValidator("_validator_get_prm"),
        # output_param=restapi.CerberusValidator("_validator_get_return_productor"),
        cors="*",
        crsf=False,
    )
    def get_productor(self, _id, **params):
        """
        Retourne les courbes de production liées à une opération ou à un PRM
        dans laquelle l'utilisateur ou sa société ont le rôle de PMO
        """
        operation = self.env["acc.operation"].browse(_id).sudo()

        partner_id = self.env["res.users"].browse(self.request.uid).partner_id

        # Check rights
        role = self._get_role(operation)
        if not role.get("isProductor") and not role.get("isPmo"):
            raise AccessError(
                "User id "
                + str(role.get("id"))
                + " does not have access to "
                + "("
                + role.get("name")
                + ") for Productor role"
            )

        # Get params
        scale = params.get("scale", False)
        date_start = params.get("date_start", False)
        date_end = params.get("date_end", False)
        prm_id = params.get("prm_id", False)
        producer_id = params.get("partner_id", False)

        domain_prm = [("acc_operation_id", "=", _id), ("is_injection", "=", True)]

        if not role.get("isPmo"):
            domain_prm.append(
                ("partner_id", "in", [partner_id.id, partner_id.parent_id.id])
            )
        prm_ids = self.env["acc.counter"].sudo().search(domain_prm)

        prm_name = prm_ids.mapped(
            lambda p: {
                "id": p.id,
                "name": p.name,
                "partner_id": p.partner_id.id,
                "street": p.street,
            }
        )

        # Get producer
        producer_name = prm_ids.mapped("partner_id").mapped(
            lambda p: {
                "id": p.id,
                "name": p.name,
            }
        )

        if operation.is_data_enedis:

            if scale:
                graph_datas = operation.graph_view_type(
                    type="prod", scale=scale, prm_id=prm_id, partner_id=producer_id
                )
            elif date_start and date_end:
                graph_datas = operation.graph_view_type(
                    type="prod",
                    date_start=datetime.strptime(date_start, "%Y-%m-%d"),
                    date_end=datetime.strptime(date_end, "%Y-%m-%d"),
                    prm_id=prm_id,
                    partner_id=producer_id,
                )
            else:
                graph_datas = operation.graph_view_type(
                    type="prod", scale="week", prm_id=prm_id, partner_id=producer_id
                )
            if prm_id:
                graph_datas["name"] = (
                    "PRM n° " + self.env["acc.counter"].sudo().browse(prm_id).name
                )
            if producer_id:
                graph_datas["name"] = (
                    self.env["res.partner"].sudo().browse(producer_id).name
                )
            graph_datas["prm_id"] = prm_id
            graph_datas["partner_id"] = producer_id
        else:
            graph_datas = None

        datas = {
            "role": self._get_role(operation),
            "graph_datas": graph_datas,
            "prms": prm_name,
            "producers": producer_name,
        }
        return datas

    @restapi.method(
        [(["/<int:id>/contact"], "GET")],
        output_param=restapi.CerberusValidator("_validator_return_get_contact"),
        cors="*",
        crsf=False,
    )
    def get_contact(self, _id):
        """
        Retourne les données de l'opération
        dans laquelle l'utilisateur ou sa société sont engagés
        """
        operation = self.env["acc.operation"].browse(_id)

        role = self._get_role(operation)
        if not role.get("isIn"):
            return AccessError()

        datas = {
            "role": role,
            "id": operation.id,
            "name": operation.name,
            "email": operation.sudo().mail_contact or "",
        }

        return datas

    # ------------------------------------------------------
    # Validators
    # ------------------------------------------------------
    def _validator_get_all(self):
        return {}

    def _validator_return_get_all(self):
        return {
            "operations": {
                "type": "list",
                "schema": {
                    "type": "dict",
                    "schema": {
                        "id": {"type": "integer"},
                        "name": {"type": "string"},
                        "description": {"type": "string", "nullable": True},
                        "date_start": {"type": "date", "nullable": True},
                        "date_end": {"type": "date", "nullable": True},
                        "distribution_key": {"type": "string", "nullable": True},
                        "pmo": {"type": "string"},
                        "image": {"type": "string", "nullable": True},
                    },
                },
            },
            "news": {
                "type": "list",
                "schema": {
                    "type": "dict",
                    "schema": {
                        "id": {"type": "integer"},
                        "name": {"type": "string"},
                        "date_actu": {"type": "date"},
                        "content_html": {"type": "string", "nullable": True},
                    },
                },
            },
        }

    def _validator_get_id(self):
        return {
            "id": {"type": "integer"},
        }

    def _validator_return_get_id(self):
        return {
            "role": {
                "type": "dict",
                "schema": {
                    "id": {"type": "integer"},
                    "name": {"type": "string"},
                    "description": {"type": "string"},
                    "isIn": {"type": "boolean"},
                    "isPmo": {"type": "boolean"},
                    "isConsumer": {"type": "boolean"},
                    "isProductor": {"type": "boolean"},
                    "isDataCdc": {"type": "boolean"},
                },
            },
            "id": {"type": "integer"},
            "name": {"type": "string"},
            "date_start": {"type": "date"},
            "date_end": {"type": "date", "nullable": True},
            "distribution_key": {"type": "string", "nullable": True},
            "pmo": {"type": "string"},
            "consumer_nb": {"type": "integer"},
            "productor_nb": {"type": "integer"},
            "power_install": {"type": "float"},
            "image": {"type": "string", "nullable": True},
            "conso_tot": {"type": "float"},
            "prod_tot": {"type": "float"},
            "month": {"type": "date", "nullable": True},
            "conso_rate": {"type": "float"},
            "prod_rate": {"type": "float"},
            "news": {
                "type": "list",
                "schema": {
                    "type": "dict",
                    "schema": {
                        "id": {"type": "integer"},
                        "name": {"type": "string"},
                        "date_actu": {"type": "date", "nullable": True},
                        "content_html": {"type": "string", "nullable": True},
                    },
                },
            },
        }

    def _validator_return_get_contact(self):
        return {
            "role": {
                "type": "dict",
                "schema": {
                    "id": {"type": "integer"},
                    "name": {"type": "string"},
                    "description": {"type": "string"},
                    "isIn": {"type": "boolean"},
                    "isPmo": {"type": "boolean"},
                    "isConsumer": {"type": "boolean"},
                    "isProductor": {"type": "boolean"},
                    "isDataCdc": {"type": "boolean"},
                },
            },
            "id": {"type": "integer"},
            "name": {"type": "string"},
            "email": {"type": "string", "nullable": True},
        }

    def _validator_get_doc(self):
        return {
            "id": {"type": "integer"},
        }

    def _validator_return_get_doc(self):
        return {
            "role": {
                "type": "dict",
                "schema": {
                    "id": {"type": "integer"},
                    "name": {"type": "string"},
                    "description": {"type": "string"},
                    "isIn": {"type": "boolean"},
                    "isPmo": {"type": "boolean"},
                    "isConsumer": {"type": "boolean"},
                    "isProductor": {"type": "boolean"},
                    "isDataCdc": {"type": "boolean"},
                },
            },
            "id": {"type": "integer"},
            "invoice_exist": {"type": "boolean"},
            "contract_exist": {"type": "boolean"},
            "name": {"type": "string"},
            "documents": {
                "nullable": True,
                "type": "list",
                "schema": {
                    "type": "dict",
                    "schema": {
                        "id": {"type": "integer"},
                        "name": {"type": "string"},
                        "date": {"type": "date", "nullable": True},
                        "start_date": {"type": "date", "nullable": True},
                        "end_date": {"type": "date", "nullable": True},
                        "amount_total": {"type": "float", "nullable": True},
                        "url": {"type": "string", "nullable": True},
                        "consumer": {"type": "string", "nullable": True},
                        "prm_c": {"type": "string", "nullable": True},
                    },
                },
            },
            "factures_externes": {
                "nullable": True,
                "type": "list",
                "schema": {
                    "type": "dict",
                    "schema": {
                        "id": {"type": "integer"},
                        "name": {"type": "string"},
                        "type": {"type": "string", "nullable": True},
                        "url": {"type": "string", "nullable": True},
                        "seller": {"type": "string", "nullable": True},
                        "buyer": {"type": "string", "nullable": True},
                    },
                },
            },
            "contracts": {
                "nullable": True,
                "type": "list",
                "schema": {
                    "type": "dict",
                    "schema": {
                        "id": {"type": "integer"},
                        "name": {"type": "string"},
                        "type": {"type": "string", "nullable": True},
                        "url": {"type": "string", "nullable": True},
                        "seller": {"type": "string", "nullable": True},
                        "buyer": {"type": "string", "nullable": True},
                    },
                },
            },
            "contracts_pmo": {
                "nullable": True,
                "type": "list",
                "schema": {
                    "type": "dict",
                    "schema": {
                        "id": {"type": "integer"},
                        "name": {"type": "string"},
                        "type": {"type": "string", "nullable": True},
                        "url": {"type": "string", "nullable": True},
                        "seller": {"type": "string", "nullable": True},
                        "buyer": {"type": "string", "nullable": True},
                    },
                },
            },
        }

    def _validator_get_pmo(self):
        return {
            "id": {"type": "integer"},
            "scale": {"type": "string", "nullable": True},
            "date_start": {"type": "string", "nullable": True},
            "date_end": {"type": "string", "nullable": True},
        }

    def _validator_get_return_pmo(self):
        return {
            "role": {
                "type": "dict",
                "schema": {
                    "id": {"type": "integer"},
                    "name": {"type": "string"},
                    "description": {"type": "string"},
                    "isIn": {"type": "boolean"},
                    "isPmo": {"type": "boolean"},
                    "isConsumer": {"type": "boolean"},
                    "isProductor": {"type": "boolean"},
                    "isDataCdc": {"type": "boolean"},
                },
            },
            "graph_data": {
                "type": "dict",
                "schema": {
                    "line_chart_prod_line": {"type": "string", "nullable": True},
                    "line_chart_conso_line": {"type": "string", "nullable": True},
                    "line_chart_prod_prm": {"type": "string", "nullable": True},
                    "donuts_chart_prod": {"type": "string", "nullable": True},
                    "donuts_chart_conso": {"type": "string", "nullable": True},
                    "histo_chart_prod": {"type": "string", "nullable": True},
                    "histo_chart_conso": {"type": "string", "nullable": True},
                    "date_start": {"type": "date", "nullable": True},
                    "date_end": {"type": "date", "nullable": True},
                    "date_min": {"type": "date", "nullable": True},
                    "date_max": {"type": "date", "nullable": True},
                    "scale": {"type": "string", "nullable": True},
                },
            },
        }

    def _validator_get_return_consumer(self):
        return {
            "role": {
                "type": "dict",
                "schema": {
                    "id": {"type": "integer"},
                    "name": {"type": "string"},
                    "description": {"type": "string"},
                    "isIn": {"type": "boolean"},
                    "isPmo": {"type": "boolean"},
                    "isConsumer": {"type": "boolean"},
                    "isProductor": {"type": "boolean"},
                    "isDataCdc": {"type": "boolean"},
                },
            },
            "prms": {
                "type": "list",
                "schema": {
                    "type": "dict",
                    "schema": {
                        "id": {"type": "integer"},
                        "name": {"type": "string"},
                        "partner_id": {"type": "integer"},
                    },
                },
            },
            "consumers": {
                "type": "list",
                "schema": {
                    "type": "dict",
                    "schema": {
                        "id": {"type": "integer"},
                        "name": {"type": "string"},
                    },
                },
            },
            "graph_data": {
                "type": "dict",
                "schema": {
                    "line_chart_prod_line": {"type": "string", "nullable": True},
                    "line_chart_conso_line": {"type": "string", "nullable": True},
                    "line_chart_prod_prm": {"type": "string", "nullable": True},
                    "donuts_chart_prod": {"type": "string", "nullable": True},
                    "donuts_chart_conso": {"type": "string", "nullable": True},
                    "histo_chart_prod": {"type": "string", "nullable": True},
                    "histo_chart_conso": {"type": "string", "nullable": True},
                    "date_start": {"type": "date", "nullable": True},
                    "date_end": {"type": "date", "nullable": True},
                    "date_min": {"type": "date", "nullable": True},
                    "date_max": {"type": "date", "nullable": True},
                    "scale": {"type": "string", "nullable": True},
                    "name": {"type": "string", "nullable": True},
                    "prm_id": {"type": "integer", "nullable": True},
                    "partner_id": {"type": "integer", "nullable": True},
                },
            },
        }

    def _validator_get_return_productor(self):
        return {
            "role": {
                "type": "dict",
                "schema": {
                    "id": {"type": "integer"},
                    "name": {"type": "string"},
                    "description": {"type": "string"},
                    "isIn": {"type": "boolean"},
                    "isPmo": {"type": "boolean"},
                    "isConsumer": {"type": "boolean"},
                    "isProductor": {"type": "boolean"},
                    "isDataCdc": {"type": "boolean"},
                },
            },
            "prms": {
                "type": "list",
                "schema": {
                    "type": "dict",
                    "schema": {
                        "id": {"type": "integer"},
                        "name": {"type": "string"},
                        "partner_id": {"type": "integer"},
                    },
                },
            },
            "producers": {
                "type": "list",
                "schema": {
                    "type": "dict",
                    "schema": {
                        "id": {"type": "integer"},
                        "name": {"type": "string"},
                    },
                },
            },
            "graph_data": {
                "type": "dict",
                "schema": {
                    "line_chart_prod_line": {"type": "string", "nullable": True},
                    "line_chart_conso_line": {"type": "string", "nullable": True},
                    "line_chart_prod_prm": {"type": "string", "nullable": True},
                    "donuts_chart_prod": {"type": "string", "nullable": True},
                    "donuts_chart_conso": {"type": "string", "nullable": True},
                    "histo_chart_prod": {"type": "string", "nullable": True},
                    "histo_chart_conso": {"type": "string", "nullable": True},
                    "date_start": {"type": "date", "nullable": True},
                    "date_end": {"type": "string", "nullable": True},
                    "date_min": {"type": "date", "nullable": True},
                    "date_max": {"type": "date", "nullable": True},
                    "scale": {"type": "string", "nullable": True},
                    "name": {"type": "string", "nullable": True},
                    "prm_id": {"type": "integer", "nullable": True},
                    "partner_id": {"type": "integer", "nullable": True},
                },
            },
        }

    def _validator_get_prm(self):
        return {
            "id": {"type": "integer"},
            "scale": {"type": "string", "nullable": True},
            "date_start": {"type": "string", "nullable": True},
            "date_end": {"type": "string", "nullable": True},
            "prm_id": {"type": "integer", "nullable": True},
            "partner_id": {"type": "integer", "nullable": True},
        }

    # ------------------------------------------------------
    # Common Function
    # ------------------------------------------------------
    def _get_role(self, operation_id):
        role = {
            "id": operation_id.id,
            "name": operation_id.name,
            "description": operation_id.description,
            "isIn": False,
            "isPmo": False,
            "isConsumer": False,
            "isProductor": False,
            "isDataCdc": False
        }

        # check if data exists to display tab
        last_record = self.env["acc.enedis.cdc"].search([
            ("acc_operation_id", "=", operation_id.id)])
        if last_record:
            role["isDataCdc"] = True

        # Get partner from user and parent
        partner_ids = self.env["res.users"].browse(self.request.uid).partner_id

        if partner_ids.parent_id:
            partner_ids += partner_ids.parent_id

        if operation_id.pmo_id in partner_ids:
            role["isPmo"] = True
            role["isIn"] = True
            role["isConsumer"] = True
            role["isProductor"] = True
            return role

        consumer_ids = operation_id.acc_delivery_ids.mapped("partner_id")
        if list(set(consumer_ids) & set(partner_ids)):
            role["isConsumer"] = True
            role["isIn"] = True

        productor_ids = operation_id.acc_injection_ids.mapped("partner_id")
        if list(set(productor_ids) & set(partner_ids)):
            role["isProductor"] = True
            role["isIn"] = True

        return role