from typing import Iterator

from constance import config
from django.db import transaction

from intranet.femida.src.notifications.offers import (
    notify_hr_about_docs_processing_problem,
    send_docs_request_message_to_candidate,
)
from intranet.femida.src.offers.choices import (
    DOCUMENT_TYPES,
    OFFER_STATUSES,
    OFFER_DOCS_PROCESSING_STATUSES,
    OFFER_DOCS_PROCESSING_RESOLUTIONS,
)
from intranet.femida.src.offers.controllers import (
    OfferCtl,
    create_oebs_person_and_assignment,
)
from intranet.femida.src.offers.helpers import get_candidate_alive_verifications_prefetch
from intranet.femida.src.offers.models import Offer
from intranet.femida.src.offers.yang.helpers import (
    get_yang_error_list,
    get_yang_processed_doc_data,
    get_yang_unprocessed_doc_data_fields,
    is_yang_unprocessable,
)
from intranet.femida.src.utils.datetime import shifted_now


def update_offers_from_yt(data: Iterator):
    """
    Забираем в офферы распознанные поля. Реагируем, если не все удалось распознать.
    На один оффер в таблице может быть несколько строк. Берем строку текущего запроса.
    """
    offer_rows_map = {
        (row['offer_id'], row['docs_request_count']): row
        for row in data
    }
    offers = (
        Offer.unsafe
        .filter(
            status=OFFER_STATUSES.accepted,
            docs_processing_status=OFFER_DOCS_PROCESSING_STATUSES.in_progress,
        )
        .select_related(
            'payment_currency',
            'profile',
            'vacancy__instead_of',
            'position',
            'candidate',
        )
        .prefetch_related(
            get_candidate_alive_verifications_prefetch(),
        )
    )
    for offer in offers:
        offer_row = offer_rows_map.get((offer.id, offer.docs_request_count))
        if not offer_row:
            continue

        _process_offer_row(offer, offer_row)


@transaction.atomic
def _process_offer_row(offer, offer_row):
    ctl = OfferCtl(offer)
    offer_data = get_yang_processed_doc_data(offer_row)
    unprocessed_fields = get_yang_unprocessed_doc_data_fields(offer)
    has_all_documents = unprocessed_fields.issubset(offer_data)
    if has_all_documents:
        offer_data['docs_processing_status'] = OFFER_DOCS_PROCESSING_STATUSES.finished
        offer_data['docs_processing_resolution'] = OFFER_DOCS_PROCESSING_RESOLUTIONS.processed
        ctl.update(offer_data)
        document_type = offer.passport_data['document_type']
        if document_type == DOCUMENT_TYPES.russian_passport:
            create_oebs_person_and_assignment(offer)
        elif document_type == DOCUMENT_TYPES.other:
            notify_hr_about_docs_processing_problem(offer)
    else:
        is_dead_end = (
            offer.docs_request_count >= config.OFFER_DOCS_REQUEST_LIMIT
            or is_yang_unprocessable(offer_row)
        )
        if is_dead_end:
            offer_data['docs_processing_status'] = OFFER_DOCS_PROCESSING_STATUSES.finished
            offer_data['docs_processing_resolution'] = OFFER_DOCS_PROCESSING_RESOLUTIONS.failed
            ctl.update(offer_data)
            notify_hr_about_docs_processing_problem(offer)
        else:
            offer_data['docs_processing_status'] = OFFER_DOCS_PROCESSING_STATUSES.need_information
            offer_data['docs_request_count'] = offer.docs_request_count + 1
            ctl.update(offer_data)
            ctl.create_link()
            ctl.activate_link(expiration_time=shifted_now(hours=config.DOCS_REQUEST_TIMEOUT_HOURS))
            send_docs_request_message_to_candidate(
                offer=offer,
                link_url=ctl.link.url,
                errors=get_yang_error_list(offer_row),
            )
