#!/usr/bin/env python
# -*- coding: utf-8 -*-

import json
import requests
import urllib.parse

from collections import UserDict
from deprecated import deprecated
from pagerduty_api.escalation_policies_client import PagerDutyEscalationPoliciesClient
from pagerduty_api.on_calls_client import PagerDutyOnCallsClient
from pagerduty_api.services_client import PagerDutyServicesClient
from pagerduty_api.tags_client import PagerDutyTagsClient
from pagerduty_api.teams_client import PagerDutyTeamsClient
from pagerduty_api.users_client import PagerDutyUsersClient
from pagerduty_api.utils import is_service_name_compliant, get_t_appid_from_service_name, dedup_entities, build_resolved_service_dict
from typing import Any, Dict, List, Tuple

DEPRECATION_VERSION = '0.1.0'
DEPRECATION_REASON = 'The PagerDutyClient has been deprecated in favor of endpoint specific clients'


class PagerDutyClient():
    '''
    DEPRECATION WARNING:
    This PagerDutyClient has been broken out into separate classes, the PagerDutyClient itself is
    deprecated.

    The functions implemented on this class are maintained for backwards compatibility, but simply
    pass through to the appropriate client.
    '''

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def __init__(self,
                 http_session: requests.Session = requests.Session(),
                 token: str = '',
                 endpoint: str = 'https://api.pagerduty.com',
                 **kwargs) -> None:
        """Create a PagerDutyClient object and assert its config
        """
        self._http_session = http_session
        self._token = token
        self._endpoint = endpoint
        assert self._token, 'Class variable token must not be empty'

        self._escalation_policies_client = PagerDutyEscalationPoliciesClient(
            http_session=http_session, endpoint=endpoint, auth_token=token
        )
        self._on_calls_client = PagerDutyOnCallsClient(
            http_session=http_session, endpoint=endpoint, auth_token=token
        )
        self._services_client = PagerDutyServicesClient(
            http_session=http_session, endpoint=endpoint, auth_token=token
        )
        self._tags_client = PagerDutyTagsClient(
            http_session=http_session, endpoint=endpoint, auth_token=token
        )
        self._teams_client = PagerDutyTeamsClient(
            http_session=http_session, endpoint=endpoint, auth_token=token
        )
        self._users_client = PagerDutyUsersClient(
            http_session=http_session, endpoint=endpoint, auth_token=token
        )

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def get_user_by_id(self, id: str) -> list:
        """
        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> records = client.get_user_by_id('PLPW2R0')
        Executing HTTP get on https://api.pagerduty.com/users/PLPW2R0
        >>> len(records) == 1
        True
        """
        return self._users_client.get_user_by_id(id)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def get_user_by_email(self, email: str) -> list:
        """
        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> records = client.get_user_by_email('john.torres@pearson.com')
        Executing HTTP get on https://api.pagerduty.com/users
        >>> len(records) == 1
        True
        >>> records[0].get('email').lower()
        'john.torres@pearson.com'
        """
        return self._users_client.get_user_by_email(email)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def is_valid_user(self, email: str) -> bool:
        """
        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> client.is_valid_user('john.torres@pearson.com')
        Executing HTTP get on https://api.pagerduty.com/users
        True
        >>> client.is_valid_user(None)
        Executing HTTP get on https://api.pagerduty.com/users
        False
        """
        return self._users_client.is_valid_user(email)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def is_member_of_team(self,
                          team_id: str = "",
                          user_id: str = "") -> bool:
        """
        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> client.is_member_of_team(team_id='PUE38G0',user_id='PN5ECJH')
        Executing HTTP get on https://api.pagerduty.com/teams/PUE38G0/members
        True
        >>> client.is_member_of_team(team_id='PUE38G0',user_id=None)
        Executing HTTP get on https://api.pagerduty.com/teams/PUE38G0/members
        False
        """
        return self._teams_client.is_member_of_team(team_id, user_id)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def get_escalation_policies_by_name(self,
                                        policy_name: str = "") -> Tuple:
        """
        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> records = client.get_escalation_policies_by_name('AISO-Tech')
        Executing HTTP get on https://api.pagerduty.com/escalation_policies
        >>> len(records) == 1
        True
        >>> records[0].get('name').lower()
        'aiso-tech'
        """
        return self._escalation_policies_client.get_escalation_policies_by_name(policy_name)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def get_on_call_for_team(self,
                             escalation_policy_id: str = "") -> dict:
        """
        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> records = client.get_on_call_for_team('PNBTQC7')
        Executing HTTP get on https://api.pagerduty.com/oncalls
        >>> len(records) == 3
        True
        """
        return self._on_calls_client.get_on_call_for_team(escalation_policy_id)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def list_services(self,
                      filter: Dict = {},
                      limit: int = 50):
        """Get a list of PD services
        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> services = client.list_services()
        Executing HTTP get on https://api.pagerduty.com/services
        >>> len(services) >= 400
        True
        >>> services[0]['name']
        '3PL-CG'
        >>> filtered = list({'id': service.get('id'), 'name':service.get('name'), 'summary':service.get('summary'), 'teams':service.get('teams')} for service in services )
        >>> filtered[0].get('summary')
        '3PL-CG'
        """
        return self._services_client.list_services(limit=limit)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def list_escalation_policies(self,
                                 limit: int = 100,
                                 params: dict = None,
                                 paginate: bool = True) -> Tuple:
        """List PagerDuty escalation policies
        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> policies = client.list_escalation_policies(limit=10,paginate=False)
        Executing HTTP get on https://api.pagerduty.com/escalation_policies
        >>> filtered = list({'id': policy.get('id'), 'name': policy.get('name'), 'summary': policy.get('summary'), 'teams': policy.get('teams')} for  policy in  policies )
        >>> filtered[0]
        {'id': 'PCCNTY7', 'name': 'AISO-Tech', 'summary': 'AISO-Tech', 'teams': [{'id': 'PKIEAG4', 'type': 'team_reference', 'summary': 'AISO-Tech', 'self': 'https://api.pagerduty.com/teams/PKIEAG4', 'html_url': 'https://pearsonai.pagerduty.com/teams/PKIEAG4'}]}
        >>> len(policies) == 10
        True
        """
        return self._escalation_policies_client.list_escalation_policies(limit, params, paginate)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def get_service_with_team_for_t_appid(self,
                                          filter: dict = None,
                                          limit: int = 100):
        """ Make this an athena wrapper based off qualys patterns
        """
        pass

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def generate_t_appid_to_service_teams(self,
                                          limit: int = 100):
        """Get a list of PD services
        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> services = client.generate_t_appid_to_service_teams(limit=100)
        Executing HTTP get on https://api.pagerduty.com/services
        Executing HTTP get on https://api.pagerduty.com/users
        >>> len(services) > 50
        True
        >>> output = open('service_teams_index.json', 'w')
        >>> output.write(json.dumps(services)) > 0
        True
        >>> output.close()
        """
        resolved_services = {}
        resolved_teams = {}

        # FIXME: sometimes a t_AppID has multiple pagerduty services. Need to capture that
        for service in self._services_client.list_compliant_services():
            t_appid = get_t_appid_from_service_name(service['name'])
            resolved_services[t_appid] = build_resolved_service_dict(service)
            for team in service['teams']:
                resolved_teams[team['id']] = team

        users = self._users_client.list_users_by_team(
            team_ids=resolved_teams.keys()
        )
        for t_appid, service in resolved_services.items():
            service_users = []
            for team in service.get('teams', []):
                for user in users.get(team['id'], []):
                    # Remove unneeded user attributes
                    user.pop('contact_methods', None)
                    user.pop('notification_rules', None)
                    user.pop('coordinated_incidents', None)
                    service_users.append(user)
            service['sre'] = dedup_entities(service_users)

        return resolved_services

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def list_tags(self,
                  limit: int = 100,
                  params: dict = None,
                  paginate: bool = True) -> Tuple:
        """List PagerDuty escalation policies
        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> tags = client.list_tags(limit=10,paginate=False)
        Executing HTTP get on https://api.pagerduty.com/tags
        >>> filtered = list({'id': tag.get('id'), 'name': tag.get('label'), 'summary': tag.get('summary')} for  tag in  tags )
        >>> filtered[0]
        {'id': 'PVLSZDV', 'name': '3PL-CG', 'summary': '3PL-CG'}
        """
        return self._tags_client.list_tags(limit, params, paginate)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def get_tag(self,
                id: str = '',
                entity: str = '',
                params: dict = None):
        """Get a team from PD
        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> client.get_tag(id='PFEH2MK').get('id') == 'PFEH2MK'
        Executing HTTP get on https://api.pagerduty.com/tags/PFEH2MK
        True
        """
        return self._tags_client.get_tag(id, params)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def get_entity_tags(self,
                        id: str = '',
                        entity: str = '',
                        params: dict = None):
        """Get a team from PD
        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> client.get_entity_tags(id='P7Y2MHL', entity='teams')
        Executing HTTP get on https://api.pagerduty.com/teams/P7Y2MHL/tags
        [{'html_url': None, 'id': 'PO97B2W', 'label': 'io-notfication-rules-SVC02985-cost-team1-EHqGcdDnuZpS', 'self': 'https://api.pagerduty.com/tags/PO97B2W', 'summary': 'io-notfication-rules-SVC02985-cost-team1-EHqGcdDnuZpS', 'type': 'tag'}]

        """
        url = f'{self._endpoint}/{entity}'
        return self._tags_client.get_entity_tags(url=url, entity_id=id, params=params)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def create_tag(self, label: str = "", summary: str = ""):
        '''No doctest so we don't affect state in production PagerDuty'''
        return self._tags_client.create_tag(label, summary)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def delete_tag(self, id: str = ""):
        '''No doctest so we don't affect state in production PagerDuty'''
        return self._tags_client.delete_tag(id)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def modify_entity_tags(self,
                           id: str = "",
                           entity: str = "",
                           assignments: dict = None):
        '''No doctest so we don't affect state in production PagerDuty'''
        return self._tags_client.modify_entity_tags(id, entity, assignments)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def list_teams(self,
                   limit: int = 100,
                   paginate: bool = True):
        """Get a list of PD services

        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> records = client.list_teams(limit=10, paginate=False)
        Executing HTTP get on https://api.pagerduty.com/teams
        >>> len(records) == 10
        True
        >>> records[0]
        {'id': 'PKIEAG4', 'name': 'AISO-Tech', 'description': None, 'type': 'team', 'summary': 'AISO-Tech', 'self': 'https://api.pagerduty.com/teams/PKIEAG4', 'html_url': 'https://pearsonai.pagerduty.com/teams/PKIEAG4', 'default_role': 'manager', 'parent': None}
        >>> filtered = list({'id': record.get('id'), 'name':record.get('name'), 'summary':record.get('summary')} for record in records )
        >>> filtered[0].get('summary')
        'AISO-Tech'
        """
        return self._teams_client.list_teams(limit, paginate)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def get_team(self,
                 id: str,
                 with_members: bool = False,
                 params: dict = None):
        """Get a team from PD
        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> client.get_team('PS54O87').get('id') == 'PS54O87'
        Executing HTTP get on https://api.pagerduty.com/teams/PS54O87
        True
        >>> 'members' in client.get_team('PS54O87', with_members=True)
        Executing HTTP get on https://api.pagerduty.com/teams/PS54O87
        Executing HTTP get on https://api.pagerduty.com/teams/PS54O87/members
        True
        """
        return self._teams_client.get_team(id, with_members, params)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def create_team(self, name: str = "", description: str = "", summary: str = ""):
        '''No doctest so we don't affect state in production PagerDuty'''
        return self._teams_client.create_team(name, description, summary)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def delete_team(self, id: str = ""):
        '''No doctest so we don't affect state in production PagerDuty'''
        return self._teams_client.delete_team(id)

    @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_REASON)
    def list_users(self,
                   team_ids: List[str] = None,
                   limit: int = 100,
                   paginate: bool = True):
        """Get a list of PD users
        >>> import os
        >>> auth_token = os.environ.get('AUTH_TOKEN')
        >>> client = PagerDutyClient(token=auth_token)
        >>> records = client.list_users(limit=10,paginate=False)
        Executing HTTP get on https://api.pagerduty.com/users
        >>> len(records) == 10
        True
        >>> records[0].get('name')[0].lower().startswith('a')
        True
        >>> lookup_teams_id: list = ['PIB9SYN','PH0LEI5']
        >>> records = client.list_users(limit=10,paginate=False,team_ids=lookup_teams_id)
        Executing HTTP get on https://api.pagerduty.com/users
        >>> list(record.get('email') for record in records if record.get('email').lower() == 'john.torres@pearson.com')
        ['john.torres@pearson.com']
        """
        return self._users_client.list_users(team_ids, limit, paginate)
