import re
from pprint import pprint

from django.core.management.base import BaseCommand
from tqdm import tqdm

from establishment.models import Establishment
from location.models import City
from location.models import WineRegion
from product.models import Product
from review.models import Review
from tag.models import Tag
from transfer.models import GuideElements


def decorator(f):
    def decorate(self):
        print(f'{"-"*20}start {f.__name__}{"-"*20}')
        f(self)
        print(f'{"-"*20}end {f.__name__}{"-"*20}\n')
    return decorate


class Command(BaseCommand):
    help = """Check guide dependencies."""

    @decorator
    def count_of_guide_relative_dependencies(self):
        for field in GuideElements._meta.fields:
            if field.name not in ['id', 'lft', 'rgt', 'depth',
                                  'children_count', 'parent', 'order_number']:
                filters = {f'{field.name}__isnull': False, }
                qs = GuideElements.objects.filter(**filters).values_list(field.name, flat=True)
                print(f"COUNT OF {field.name}'s: {len(set(qs))}")

    @decorator
    def check_regions(self):
        wine_region_old_ids = set(GuideElements.objects.filter(wine_region_id__isnull=False)
                                                       .values_list('wine_region_id', flat=True))
        not_existed_wine_regions = []
        for old_id in tqdm(wine_region_old_ids):
            if not WineRegion.objects.filter(old_id=old_id).exists():
                not_existed_wine_regions.append(old_id)
        print(f'NOT EXISTED WINE REGIONS: {len(not_existed_wine_regions)}')
        pprint(f'{not_existed_wine_regions}')

    @decorator
    def check_establishments(self):
        establishment_old_ids = set(GuideElements.objects.filter(establishment_id__isnull=False)
                                    .values_list('establishment_id', flat=True))
        not_existed_establishments = []
        for old_id in tqdm(establishment_old_ids):
            if not Establishment.objects.filter(old_id=old_id).exists():
                not_existed_establishments.append(old_id)
        print(f'NOT EXISTED ESTABLISHMENTS: {len(not_existed_establishments)}')
        pprint(f'{not_existed_establishments}')

    @decorator
    def check_reviews(self):
        review_old_ids = set(GuideElements.objects.filter(review_id__isnull=False)
                                                  .values_list('review_id', flat=True))
        not_existed_reviews = []
        for old_id in tqdm(review_old_ids):
            if not Review.objects.filter(old_id=old_id).exists():
                not_existed_reviews.append(old_id)
        print(f'NOT EXISTED REVIEWS: {len(not_existed_reviews)}')
        pprint(f'{not_existed_reviews}')

    @decorator
    def check_wines(self):
        wine_old_ids = set(GuideElements.objects.filter(wine_id__isnull=False)
                           .values_list('wine_id', flat=True))
        not_existed_wines = []
        for old_id in tqdm(wine_old_ids):
            if not Product.objects.filter(old_id=old_id).exists():
                not_existed_wines.append(old_id)
        print(f'NOT EXISTED WINES: {len(not_existed_wines)}')
        pprint(f'{not_existed_wines}')

    @decorator
    def check_wine_color(self):
        raw_wine_color_nodes = set(GuideElements.objects.exclude(color__iexact='')
                                                        .filter(color__isnull=False)
                                                        .values_list('color', flat=True))
        raw_wine_colors = [i[:-11] for i in raw_wine_color_nodes]
        raw_wine_color_index_names = []
        re_exp = '[A-Z][^A-Z]*'
        for raw_wine_color in tqdm(raw_wine_colors):
            result = re.findall(re_exp, rf'{raw_wine_color}')
            if result and len(result) >= 2:
                wine_color = '-'.join(result)
            else:
                wine_color = result[0]
            raw_wine_color_index_names.append(wine_color.lower())
        not_existed_wine_colors = []
        for index_name in raw_wine_color_index_names:
            if not Tag.objects.filter(value=index_name).exists():
                not_existed_wine_colors.append(index_name)
        print(f'NOT EXISTED WINE COLOR: {len(not_existed_wine_colors)}')
        pprint(f'{not_existed_wine_colors}')

    @decorator
    def check_cities(self):
        city_old_ids = set(GuideElements.objects.filter(city_id__isnull=False)
                           .values_list('city_id', flat=True))
        not_existed_cities = []
        for old_id in tqdm(city_old_ids):
            if not City.objects.filter(old_id=old_id).exists():
                not_existed_cities.append(old_id)
        print(f'NOT EXISTED CITIES: {len(not_existed_cities)}')
        pprint(f'{not_existed_cities}')

    def handle(self, *args, **kwargs):
        self.count_of_guide_relative_dependencies()
        self.check_regions()
        self.check_establishments()
        self.check_reviews()
        self.check_wines()
        self.check_wine_color()
        self.check_cities()
