#  Licensed to the Apache Software Foundation (ASF) under one or more
#  contributor license agreements. See the NOTICE file distributed with
#  this work for additional information regarding copyright ownership.
#  The ASF licenses this file to You under the Apache License, Version 2.0
#  (the "License"); you may not use this file except in compliance with
#  the License. You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

import copy
import json
from typing import Any, Dict, List, Optional

from metadata.ingestion.models.json_serializable import JsonSerializable

UNQUOTED_SUFFIX = ":UNQUOTED"


class User(JsonSerializable):
    """
    User model. This model doesn't define any relationship.
    """

    USER_NODE_LABEL = "User"
    USER_NODE_KEY_FORMAT = "{email}"
    USER_NODE_EMAIL = "email"
    USER_NODE_FIRST_NAME = "first_name"
    USER_NODE_LAST_NAME = "last_name"
    USER_NODE_FULL_NAME = "full_name"
    USER_NODE_GITHUB_NAME = "github_username"
    USER_NODE_TEAM = "team_name"
    USER_NODE_EMPLOYEE_TYPE = "employee_type"
    USER_NODE_MANAGER_EMAIL = "manager_email"
    USER_NODE_SLACK_ID = "slack_id"
    USER_NODE_IS_ACTIVE = "is_active{}".format(
        UNQUOTED_SUFFIX
    )  # bool value needs to be unquoted when publish to neo4j
    USER_NODE_UPDATED_AT = "updated_at"
    USER_NODE_ROLE_NAME = "role_name"

    USER_MANAGER_RELATION_TYPE = "MANAGE_BY"
    MANAGER_USER_RELATION_TYPE = "MANAGE"

    def __init__(
        self,
        email: str,
        first_name: str = "",
        last_name: str = "",
        name: str = "",
        github_username: str = "",
        team_name: str = "",
        employee_type: str = "",
        manager_email: str = "",
        slack_id: str = "",
        is_active: bool = True,
        updated_at: int = 0,
        role_name: str = "",
        do_not_update_empty_attribute: bool = False,
        **kwargs: Any
    ) -> None:
        """
        This class models user node for Amundsen people.

        :param first_name:
        :param last_name:
        :param name:
        :param email:
        :param github_username:
        :param team_name:
        :param employee_type:
        :param manager_email:
        :param is_active:
        :param updated_at: everytime we update the node, we will push the timestamp.
                           then we will have a cron job to update the ex-employee nodes based on
                           the case if this timestamp hasn't been updated for two weeks.
        :param role_name: the role_name of the user (e.g swe)
        :param do_not_update_empty_attribute: If False, all empty or not defined params will be overwritten with
        empty string.
        :param kwargs: Any K/V attributes we want to update the
        """
        self.first_name = first_name
        self.last_name = last_name
        self.name = name

        self.email = email
        self.github_username = github_username
        # todo: team will be a separate node once Amundsen People supports team
        self.team_name = team_name
        self.manager_email = manager_email
        self.employee_type = employee_type
        # this attr not available in team service, either update team service, update with FE
        self.slack_id = slack_id
        self.is_active = is_active
        self.updated_at = updated_at
        self.role_name = role_name
        self.do_not_update_empty_attribute = do_not_update_empty_attribute
        self.attrs = None
        if kwargs:
            self.attrs = copy.deepcopy(kwargs)


class MetadataUser(JsonSerializable):
    """
    Catalog User model. This model doesn't define any relationship.
    """

    def __init__(
        self,
        name: str,
        display_name: str,
        email: str,
        timezone: str = "PST",
        is_bot: bool = False,
        teams: [] = None,
        **kwargs: Any
    ) -> None:
        """ """
        self.name = name
        self.display_name = display_name
        self.email = email
        self.timezone = timezone
        self.is_bot = is_bot
        self.teams = teams
        if kwargs:
            self.attrs = copy.deepcopy(kwargs)


class MetadataOrg(JsonSerializable):
    """
    Catalog Org Model
    """

    def __init__(self, name: str, documentation: str = "") -> None:
        """ """
        self.name = name
        self.documentation = documentation


class MetadataTeam(JsonSerializable):
    """
    Catalog Team Model
    """

    def __init__(self, name: str, description: str = "") -> None:
        """ """
        self.name = name.replace(" ", "_")
        self.display_name = name
        self.description = description


class MetadataRole(JsonSerializable):
    """
    Catalog Role
    """

    def __init__(self, name: str, documentation: str = ""):
        """ """
        self.name = name
        self.documentation = documentation
