"""Collection app celery tasks."""
import logging

from celery import shared_task
from utils.methods import transform_into_readable_str

logging.basicConfig(format='[%(levelname)s] %(message)s', level=logging.INFO)
logger = logging.getLogger(__name__)


def get_additional_establishment_data(section_node, establishment):
    data = [
        section_node.id,
        establishment.id,
    ]
    if establishment.last_published_review:
        data.append(establishment.last_published_review.id)
    return data


def get_additional_product_data(section_node, product):
    data = [
        section_node.id,
        product.id,
    ]
    if product.last_published_review:
        data.append(product.last_published_review.id)
    return data


@shared_task
def generate_establishment_guide_elements(guide_id: int, filter_set: dict):
    """Generate guide elements."""
    from collection.models import GuideElement, Guide
    from establishment.models import Establishment

    guide = Guide.objects.get(id=guide_id)
    guide.change_state(Guide.BUILDING)
    queryset_values = Establishment.objects.filter(**filter_set).values()
    try:
        for instance in queryset_values:
            establishment_id = instance.get('id')
            establishment_qs = Establishment.objects.filter(id=establishment_id)
            if establishment_qs.exists():
                establishment = establishment_qs.first()
                root_node, _ = GuideElement.objects.get_or_create_root_node(guide_id)
                if root_node:
                    city_node, _ = GuideElement.objects.get_or_create_city_node(root_node.id,
                                                                                establishment.address.city_id)
                    if city_node:
                        section_node, _ = GuideElement.objects.get_or_create_establishment_section_node(
                            city_node.id,
                            transform_into_readable_str(establishment.establishment_type.index_name),
                        )
                        if section_node:
                            GuideElement.objects.get_or_create_establishment_node(
                                *get_additional_establishment_data(section_node=section_node,
                                                                   establishment=establishment))
                        else:
                            logger.error(
                                f'METHOD_NAME: {generate_establishment_guide_elements.__name__}\n'
                                f'DETAIL: Guide ID {guide_id} - SectionNode is not exists.')
                    else:
                        logger.error(f'METHOD_NAME: {generate_establishment_guide_elements.__name__}\n'
                                     f'DETAIL: Guide ID {guide_id} - CityNode is not exists.')
                else:
                    logger.error(f'METHOD_NAME: {generate_establishment_guide_elements.__name__}\n'
                                 f'DETAIL: Guide ID {guide_id} - RootNode is not exists.')
            else:
                logger.error(f'METHOD_NAME: {generate_establishment_guide_elements.__name__}\n'
                             f'DETAIL: Guide ID {guide_id} - Establishment {establishment_id} id is not exists.')
    except Exception as e:
        guide.change_state(Guide.WAITING)
        logger.error(f'METHOD_NAME: {generate_establishment_guide_elements.__name__}\n'
                     f'DETAIL: Guide ID {guide_id} - {e}')
    else:
        guide.update_count_related_objects()
        guide.change_state(Guide.BUILT)


@shared_task
def generate_product_guide_elements(guide_id: int, filter_set: dict):
    """Generate guide elements."""
    from collection.models import GuideElement, Guide
    from product.models import Product

    guide = Guide.objects.get(id=guide_id)
    guide.change_state(Guide.BUILDING)
    queryset_values = Product.objects.filter(**filter_set).values()[0]
    try:
        for instance in queryset_values:
            wine_id = instance.get('id')
            wine_qs = Product.objects.filter(id=wine_id)
            if wine_qs.exists():
                wine = wine_qs.first()
                root_node, _ = GuideElement.objects.get_or_create_root_node(guide_id)
                if root_node:
                    wine_region_node, _ = GuideElement.objects.get_or_create_wine_region_node(
                        root_node.id,
                        wine.wine_region.id)
                    if wine_region_node:
                        yard_node, _ = GuideElement.objects.get_or_create_yard_node(
                            product_id=wine.id,
                            wine_region_node_id=wine_region_node.id
                        )
                        if yard_node:
                            wine_color_qs = wine.wine_colors
                            if wine_color_qs.exists():
                                wine_color_section, _ = GuideElement.objects.get_or_create_color_wine_section_node(
                                    wine_color_name=wine_color_qs.first().value,
                                    yard_node_id=yard_node.id
                                )
                                if wine_color_section:
                                    GuideElement.objects.get_or_create_wine_node(
                                        *get_additional_product_data(
                                            section_node=wine_color_section,
                                            product=wine))
                            else:
                                logger.error(
                                    f'METHOD_NAME: {generate_product_guide_elements.__name__}\n'
                                    f'DETAIL: Guide ID {guide_id} - Wine {wine.id} has not colors.')
                    else:
                        logger.error(
                            f'METHOD_NAME: {generate_product_guide_elements.__name__}\n'
                            f'DETAIL: Guide ID {guide_id} - WineRegionNode is not exists.')
                else:
                    logger.error(f'METHOD_NAME: {generate_product_guide_elements.__name__}\n'
                                 f'DETAIL: Guide ID {guide_id} - RootNode is not exists.')
            else:
                logger.error(f'METHOD_NAME: {generate_product_guide_elements.__name__}\n'
                             f'DETAIL: Guide ID {guide_id} - Product {wine_id} id is not exists.')
    except Exception as e:
        guide.change_state(Guide.WAITING)
        logger.error(f'METHOD_NAME: {generate_product_guide_elements.__name__}\n'
                     f'DETAIL: Guide ID {guide_id} - {e}')
    else:
        guide.update_count_related_objects()
        guide.change_state(Guide.BUILT)


@shared_task
def export_guide(guide_id, user_id, file_type='csv'):
    from collection.models import GuideElement, Guide
    from collection.serializers import GuideElementExportSerializer
    from account.models import User
    from utils.export import SendGuideExport

    user = User.objects.get(id=user_id)
    guide = Guide.objects.get(id=guide_id)
    root = GuideElement.objects.get_root_node(guide)
    if root:
        nodes = root.get_descendants().select_related('review', 'establishment', 'wine_region',
                                                      'product', 'city', 'wine_color_section',
                                                      'section', 'label_photo', 'guide',
                                                      'city__country', 'establishment__establishment_type')
        serializer = GuideElementExportSerializer(nodes, many=True)
        data = serializer.data
        SendGuideExport(
            data=data, guide=guide, user=user, file_type=file_type
        ).send()
