# By: Riasat Ullah
# This file validates organization related details.

from utils import constants, integration_type_names as intt, roles, var_names
from validations import string_validator
import configuration as configs
import pytz


def validate_organization_info(organization_name, address, city, state, zip_code, country, sector, timezone, language):
    '''
    Makes sure that the basic information of an organization is valid.
    :param organization_name: name of the organization
    :param address: address of the organization
    :param city: city the organization is in
    :param state: state the organization is in
    :param zip_code: zip code of the organization's address
    :param country: 2 letter iso country code
    :param sector: sector the organization is in
    :param timezone: timezone the organization is in
    :param language: primary language of the organization
    :errors: AssertionError
    '''
    assert string_validator.is_standard_name(organization_name)
    assert string_validator.is_not_sql_injection(address)
    assert string_validator.is_standard_name(city)
    assert string_validator.is_standard_name(state)
    assert string_validator.is_zip_code(zip_code)
    assert country in list(constants.all_country_codes.keys())
    assert sector in configs.allowed_sectors
    assert timezone in pytz.all_timezones
    assert language in configs.allowed_languages


def validate_user_info(first_name, last_name, iso_code, phone_code, phone, user_timezone, user_language):
    '''
    Validates the update-able information of a user.
    :param first_name: first name of the user
    :param last_name: last name of the user
    :param iso_code: 2 letter ISO code
    :param phone_code: country code of the user's phone number
    :param phone: user's phone number including the country code (without +)
    :param user_timezone: timezone the user is in
    :param user_language: the language the user's account should be set up in
    :errors: AssertionError
    '''
    assert string_validator.is_standard_name(first_name)
    assert string_validator.is_standard_name(last_name)
    assert iso_code in list(constants.all_country_codes.keys())
    assert string_validator.is_phone_country_code(phone_code)
    assert string_validator.is_phone_number(phone)
    assert user_timezone in pytz.all_timezones
    assert user_language in configs.allowed_languages


def validate_payment_info(brand, last_four, card_token, handler, is_default):
    '''
    Validates the payment info retrieved from a payment handler after processing the information
    provided by the user.
    :param brand: the brand of the card
    :param last_four: the last four digits of the card
    :param card_token: card token from the vendor
    :param handler: the payment vendor that handles this card (Stripe, etc)
    :param is_default: (boolean) true if the card is going to be the default card or not
    :errors: AssertionError
    '''
    assert isinstance(card_token, dict)
    assert len(card_token) == 2
    assert set(list(card_token.keys())) == {var_names.customer_id, var_names.payment_method}
    assert card_token[var_names.customer_id] is not None and \
           not string_validator.is_empty_string(card_token[var_names.customer_id])
    assert card_token[var_names.payment_method] is not None and \
           not string_validator.is_empty_string(card_token[var_names.payment_method])

    assert string_validator.is_last_four_card_number(last_four)
    assert string_validator.is_not_sql_injection(brand)
    assert handler in configs.allowed_payment_handlers
    assert isinstance(is_default, bool)


def validate_notification_rules(rules):
    '''
    Validates the custom notification rules that a user requests for.
    :param rules: (dict) of rules -> { minutes_buffer: [ notification_method, ...], ...}
    :errors: AssertionError
    '''
    assert isinstance(rules, dict) and len(rules) > 0
    for min_buff in rules:
        assert isinstance(min_buff, int) and min_buff >= 0
        assert set(rules[min_buff]).issubset(set(configs.allowed_notification_methods)) and len(rules[min_buff]) > 0


def validate_organization_sso_settings(
        organization_id, integration_type, direct_login=False, auto_provision=False, role_id=None,
        saml_certificate=None, saml_key=None, login_url=None, logout_url=None, metadata_url=None, entity_id=None,
        vendor_id=None, vendor_subdomain=None, additional_info=None
):
    '''
    Validate the SSO settings of an organization
    :param organization_id: ID of the organization
    :param integration_type: the type of integration
    :param direct_login: (boolean) whether direct login with TaskCall will be allowed or not
    :param auto_provision: (boolean) whether users can be auto registered upon first SSO sign in
    :param role_id: default role id that will be associated to the new auto provisioned user
    :param saml_certificate: SAML certificate
    :param saml_key: SAML key
    :param login_url: login url to redirect to
    :param logout_url: logout url to redirect to
    :param metadata_url: SAML metadata url
    :param entity_id: SAML entity ID
    :param vendor_id: ID of the SSO vendor
    :param vendor_subdomain: the subdomain of the organization with the SSO vendor
    :param additional_info: any additional information that might be relevant
    '''
    assert isinstance(organization_id, int)
    assert integration_type in configs.allowed_sso_types
    assert isinstance(direct_login, bool)
    assert isinstance(auto_provision, bool)
    if role_id is not None:
        assert role_id in roles.user_role_maps.keys()
    if saml_certificate is not None:
        assert isinstance(saml_certificate, str)
    if saml_key is not None:
        assert isinstance(saml_key, str)
    if login_url is not None:
        assert string_validator.is_web_url(login_url)
    if logout_url is not None:
        assert string_validator.is_web_url(logout_url)
    if metadata_url is not None:
        assert string_validator.is_web_url(metadata_url)
    if entity_id is not None:
        assert isinstance(entity_id, str)
    if vendor_id is not None:
        assert isinstance(vendor_id, str)
    if vendor_subdomain is not None:
        assert isinstance(vendor_subdomain, str)
    if additional_info is not None:
        assert isinstance(additional_info, dict)
    if integration_type == intt.okta:
        assert var_names.client_id in additional_info and additional_info[var_names.client_id] is not None \
               and not string_validator.is_empty_string(additional_info[var_names.client_id])
        assert var_names.client_secret in additional_info and additional_info[var_names.client_secret] is not None \
               and not string_validator.is_empty_string(additional_info[var_names.client_secret])
