from datetime import datetime
import logging

from django.conf import settings

from staff.person.controllers import PersonCtl
from staff.person.models import Staff, StaffPhone, PHONE_TYPES, DOMAIN, VERIFY_CODE_OBJECT_TYPES, LANG
from staff.users.models import User

from staff.preprofile.crown_depriving import deprive_gold_and_silver_crown_through_proposal
from staff.preprofile.models import Preprofile, PREPROFILE_STATUS, CANDIDATE_TYPE, FORM_TYPE, EMAIL_DOMAIN


logger = logging.getLogger(__name__)


def to_staff_email_domain(domain):
    domain_map = {
        EMAIL_DOMAIN.YANDEX_TEAM_RU: DOMAIN.YANDEX_TEAM_RU,
        EMAIL_DOMAIN.YANDEX_TEAM_COM_UA: DOMAIN.YANDEX_TEAM_COM_UA,
        EMAIL_DOMAIN.YANDEX_TEAM_COM: DOMAIN.YANDEX_TEAM_COM,
        EMAIL_DOMAIN.YANDEX_TEAM_COM_TR: DOMAIN.YANDEX_TEAM_COM_TR,
        EMAIL_DOMAIN.YAMONEY_RU: DOMAIN.YAMONEY_RU,
        EMAIL_DOMAIN.YAPROBKI_RU: DOMAIN.YAPROBKI_RU,
    }

    return domain_map[domain]


def adoption_data(preprofile):
    return {
        'first_name': preprofile.first_name,
        'last_name': preprofile.last_name,
        'first_name_en': preprofile.first_name_en,
        'last_name_en': preprofile.last_name_en,
        'middle_name': preprofile.middle_name or '',
        'birthday': preprofile.birthday,
        'gender': preprofile.gender,
        'department': preprofile.department,
        'office': preprofile.office,
        'organization': preprofile.organization,
        'position': preprofile.position_staff_text,
        'employment': preprofile.employment_type,
        'preprofile_id': preprofile.id,
        'home_email': preprofile.email or '',
        'domain': to_staff_email_domain(preprofile.email_domain),
        'table': preprofile.table,
        'lang_ui': preprofile.lang_ui,
        'login_crm': preprofile.crm_alias or '',
        'date_completion_internship': preprofile.date_completion_internship,
        'auto_translate': preprofile.lang_ui != LANG.RU,
    }


def _get_or_create_phone(person: PersonCtl, user: User, preprofile: Preprofile) -> StaffPhone:
    phone = person.phones.filter(number=preprofile.phone).order_by('-for_digital_sign').first()

    if not phone:
        phone = person.phones.create(
            number=preprofile.phone,
            type=PHONE_TYPES.MOBILE,
            created_at=datetime.now(),
            modified_at=datetime.now(),
        )
        person.save(author_user=user)

    return phone


def _create_digital_sign(preprofile: Preprofile, phone: StaffPhone):
    from .tasks import create_digital_sign_task
    if not preprofile.is_eds_phone_verified:
        return
    types = VERIFY_CODE_OBJECT_TYPES
    kwargs = {
        'object_type': types.OFFER if preprofile.femida_offer_id else types.PREPROFILE,
        'object_id': preprofile.femida_offer_id or preprofile.id,
        'phone_id': phone.id,
    }
    create_digital_sign_task.apply_async(kwargs=kwargs, countdown=30)


def adopt_preprofile(preprofile_model: Preprofile, adopter: Staff):
    assert preprofile_model.status == PREPROFILE_STATUS.READY

    logger.info('Adopting preprofile %s for %s', preprofile_model.id, preprofile_model.login)
    if preprofile_model.candidate_type == CANDIDATE_TYPE.NEW_EMPLOYEE:
        logger.info('Creating staff for preprofile %s for %s', preprofile_model.id, preprofile_model.login)
        create_staff_from_model(preprofile_model, adopter)
    elif preprofile_model.candidate_type == CANDIDATE_TYPE.FORMER_EMPLOYEE:
        logger.info('Restoring staff for preprofile %s for %s', preprofile_model.id, preprofile_model.login)
        restore_staff_from_model(preprofile_model, adopter)
    elif preprofile_model.candidate_type == CANDIDATE_TYPE.EXTERNAL_EMPLOYEE:
        logger.info('Adopting staff for preprofile %s for %s', preprofile_model.id, preprofile_model.login)
        adopt_external_employee_to_yandex(preprofile_model, adopter)
    elif preprofile_model.candidate_type == CANDIDATE_TYPE.CURRENT_EMPLOYEE:
        logger.info('Rotate staff for preprofile %s for %s', preprofile_model.id, preprofile_model.login)
        rotate_person(preprofile_model, adopter)
    else:
        raise NotImplementedError()


def rotate_person(preprofile_model: Preprofile, adopter: Staff):
    assert preprofile_model.status == PREPROFILE_STATUS.READY
    person = Staff.objects.select_for_update().get(login=preprofile_model.login)
    rotate_data = adoption_data(preprofile_model)
    for non_required in ('office', 'employment'):
        if not rotate_data[non_required]:
            del rotate_data[non_required]

    deprive_gold_and_silver_crown_through_proposal(adopter, person, preprofile_model.femida_offer_id)
    PersonCtl(person).rotate(rotate_data).save(author_user=adopter.user)

    logger.info('Staff for preprofile {id} for {login} rotated, closing it'.format(
        id=preprofile_model.id,
        login=preprofile_model.login,
    ))


def restore_staff_from_model(preprofile_model: Preprofile, adopter: Staff):
    assert preprofile_model.status == PREPROFILE_STATUS.READY

    staff = Staff.objects.select_for_update().get(login=preprofile_model.login)

    restoration_data = {
        'photo': preprofile_model.photo,
    }

    restoration_data.update(adoption_data(preprofile_model))

    if staff.home_email == preprofile_model.email:
        del restoration_data['home_email']

    person = PersonCtl(staff).update(restoration_data).restore()

    person.save(author_user=adopter.user)

    if preprofile_model.phone:
        phone = _get_or_create_phone(person, adopter.user, preprofile_model)
        _create_digital_sign(preprofile_model, phone)

    logger.info('Staff for preprofile %s for %s restored, closing it', preprofile_model.id, preprofile_model.login)


def create_staff_from_model(preprofile_model, adopter):
    """
    :type preprofile_model: Preprofile
    :type adopter: Staff
    """
    assert preprofile_model.status == PREPROFILE_STATUS.READY
    assert preprofile_model.uid
    assert preprofile_model.guid

    creation_data = {
        'login': preprofile_model.login,
        'uid': preprofile_model.uid,
        'guid': preprofile_model.guid,
        'photo': preprofile_model.photo,
        'login_mail': preprofile_model.login,
    }

    creation_data.update(adoption_data(preprofile_model))

    person = PersonCtl.create(creation_data)

    author_user = adopter.user
    if preprofile_model.form_type in (FORM_TYPE.ROBOT, FORM_TYPE.ZOMBIE):
        author_user = User.objects.get(username=settings.ROBOT_STAFF_LOGIN)
    person.save(author_user=author_user)

    if preprofile_model.phone:
        phone = _get_or_create_phone(person, author_user, preprofile_model)
        _create_digital_sign(preprofile_model, phone)

    logger.info('Staff for preprofile %s for %s created, closing it', preprofile_model.id, preprofile_model.login)


def adopt_external_employee_to_yandex(preprofile_model, adopter):
    """
    :type preprofile_model: Preprofile
    :type adopter: Staff
    """
    assert 'preprofile.department is yandex'
    assert preprofile_model.status == PREPROFILE_STATUS.READY

    try:
        person = Staff.objects.select_for_update().get(login=preprofile_model.login)
    except Staff.DoesNotExist:
        logger.error(
            'Error trying to adopt person from preprofile %s',
            preprofile_model.id,
        )
        return

    data = adoption_data(preprofile_model)

    if person.home_email == preprofile_model.email:
        del data['home_email']

    deprive_gold_and_silver_crown_through_proposal(adopter, person, preprofile_model.femida_offer_id)
    person_ctl = PersonCtl(person).adopt_external_to_yandex_or_outstaff(data)
    person_ctl.save(author_user=adopter.user)

    if preprofile_model.phone:
        phone = _get_or_create_phone(person_ctl, adopter.user, preprofile_model)
        _create_digital_sign(preprofile_model, phone)

    logger.info(
        'Staff for preprofile %s for %s adopted to yandex, closing it',
        preprofile_model.id,
        preprofile_model.login,
    )
