from math import ceil
import graphene
from graphene_django import DjangoObjectType
from development.models import Development
from main.models import Language, SiteSettings
from main.graphene_tools import PageDetail
from .models import Developer, DeveloperTranslate
from django.db.models import Q, Count
from django.conf import settings
from django.db.models import Prefetch
from django.core.cache import cache

CACHE_TIME = settings.CACHE_TIME  # cache in second


class AggregateRating(graphene.ObjectType):
    type = graphene.String(default_value="AggregateRating")
    rating_value = graphene.String(default_value="10")
    best_rating = graphene.String(default_value="10")
    ratingCount = graphene.String()

    def resolve_rating_value(self, info):
        return f"{self.developer.rate}"

    def resolve_ratingCount(self, info):
        return f"{self.developer.developments.filter(is_active=True, is_deleted=False).count()}"


class DeveloperMicroData(graphene.ObjectType):
    type = graphene.String(default_value="Organization")
    name = graphene.String()
    description = graphene.String()
    url = graphene.String()
    image = graphene.String()
    aggregate_rating = graphene.Field(AggregateRating)

    def resolve_name(self, info):
        return self.developer.name

    def resolve_description(self, info):
        return self.summary

    def resolve_url(self, info):
        return self.developer.web_address

    def resolve_image(self, info):
        return f"https://file.entralon.com/{self.developer.image}"

    def resolve_aggregate_rating(self, info):
        return self


class DeveloperListingMicroData(graphene.ObjectType):
    type = graphene.String(default_value="ItemList")
    items = graphene.List(DeveloperMicroData)
    number_of_items = graphene.String()
    item_list_order = graphene.String()


class MetaTagsType(graphene.ObjectType):
    """SEO Meta Tags Schema"""
    title = graphene.String()
    description = graphene.String()
    keywords = graphene.String()
    og_title = graphene.String()
    og_description = graphene.String()
    og_image = graphene.String()
    og_type = graphene.String()
    twitter_card = graphene.String()
    twitter_title = graphene.String()
    twitter_description = graphene.String()
    twitter_image = graphene.String()
    canonical_url = graphene.String()


class DeveloperTranslateType(DjangoObjectType):
    class DevelopmentSort(graphene.Enum):
        NAME_ASC = "title"
        NAME_DESC = "-title"
        CREATED_AT_ASC = "created_at"
        CREATED_AT_DESC = "-created_at"
        RANDOM = "?"

    web_address = graphene.String()
    rate = graphene.Int()
    property_num = graphene.Int()
    is_featured = graphene.Boolean()
    image = graphene.String()
    micro_data = graphene.JSONString()
    meta_tags = graphene.Field(MetaTagsType)
    development = graphene.Field('development.schema.FilterDevelopmentType', page=graphene.Int(
    ), page_size=graphene.Int(), search=graphene.String(), featured=graphene.Boolean(), sort_by=DevelopmentSort())

    class Meta:
        model = DeveloperTranslate
        fields = ["id", "name", "slug", 'property_num', "web_address", 'is_featured',
                  'summary', 'description', "image", "rate", "created_at", "development"]
        

    @classmethod
    def get_queryset(cls, queryset, info):
        return queryset.select_related(
            'developer',
            'developer__city',
            'developer__country',
            'language'
        ).prefetch_related(
            'developer__developments',
            'development_translate'
        )

    def resolve_development(self, info, page=1, page_size=10, search=None, featured=None, sort_by=DevelopmentSort.CREATED_AT_DESC):
        if page_size > 20:
            page_size = 20
        f = Q(development__is_active=True) & Q(development__is_deleted=False)
        if featured is not None:
            f &= Q(development__is_featured=featured)
        if search is not None and search != "":
            f &= Q(development__title__icontains=search) | Q(
                development__translates__title__icontains=search)
        qs = self.development_translate.filter(f).order_by(
            "development__is_sold_out", "development__completed_date", sort_by.value)
        qs = qs.distinct()
        count = qs.count()
        pages_count = ceil(count / page_size)
        if page > pages_count:
            page = pages_count
        if page < 1:
            page = 1
        start = 0 + (page - 1) * page_size
        end = start + page_size
        has_next_page = end < count
        return {
            "node": qs[start:end],
            "page_info": {
                "has_next_page": has_next_page,
                "has_previous_page": page > 1,
                "current_page": page,
                "page_size": page_size,
                "count": count,
                "pages_count": pages_count,
            }
        }

    def resolve_id(self, info):
        return self.developer.id

    def resolve_name(self, info):
        return self.developer.name

    def resolve_slug(self, info):
        return f"developer-{self.developer.slug}"

    def resolve_rate(self, info):
        return self.developer.rate

    def resolve_is_featured(self, info):
        return self.developer.is_featured

    def resolve_image(self, info):
        try:
            return self.developer.image
        except:
            return ""

    def resolve_web_address(self, info):
        return self.developer.web_address

    def resolve_property_num(self, info):
        return self.developer.developments.filter(is_active=True, is_deleted=False).count()

    def resolve_micro_data(self, info):
        return {
            "@context": "https://schema.org",
            "@type": "Organization",
            "name": self.developer.name,
            "url": f"https://entralon.com/en/developers/developer-{self.slug}",
            "logo": f"https://file.entralon.com/{self.developer.image}",
            "address": {
                "@type": "PostalAddress",
                # "streetAddress": "Office 42, London Tower",
                "addressLocality": self.developer.city.name if self.developer.city else "",
                "addressCountry": self.developer.country.code if self.developer.country else "",
            },
            # "contactPoint": {
            #     "@type": "ContactPoint",
            #     "telephone": "+44 20 5678 1234",
            #     "contactType": "sales"
            # }
        }

    def resolve_meta_tags(self, info):
        keywords = f"{self.developer.name}, {self.name}, developer, home builder, real estate"
        base_url = "https://entralon.com"
        canonical = f"{base_url}/{self.language.code}/developers/{self.developer.slug}"
        title = self.developer.name
        summary = self.summary[:160] if self.summary else ""
        image = self.developer.image
        return {
            "title": title,
            "description": summary,
            "keywords": keywords,
            "og_title": title,
            "og_description": summary,
            "og_image": f"https://file.entralon.com/{image}",
            "og_type": "website",
            "twitter_card": "summary_large_image",
            "twitter_title": title,
            "twitter_description": summary,
            "twitter_image": f"https://file.entralon.com/{image}",
            "canonical_url": canonical
        }


class FilterDeveloperType(graphene.ObjectType):
    node = graphene.List(DeveloperTranslateType)
    page_info = graphene.Field(PageDetail)
    micro_data = graphene.JSONString()
    meta_tags = graphene.Field(MetaTagsType)

    def resolve_micro_data(self, info):
        item_list = []
        for item in self['node']:
            item_list.append({
                "@type": "ListItem",
                "position": item.id,
                "url": f"https://entralon.com/{item.language.code}/developers/developer-{item.developer.slug}",
                "name": f"{item.developer.name}",
                "image": f"https://file.entralon.com/{item.developer.image}",
                "description": item.summary,
                "item": {
                    "@context": "https://schema.org",
                    "@type": "Organization",
                    "name": item.developer.name,
                    "url": f"https://entralon.com/en/developers/developer-{item.slug}",
                    "logo": f"https://file.entralon.com/{item.developer.image}",
                    "address": {
                        "@type": "PostalAddress",
                        # "streetAddress": "Office 42, London Tower",
                        "addressLocality": item.developer.city.name if item.developer.city else "",
                        "addressCountry": item.developer.country.code if item.developer.country else "",
                    },
                    # "contactPoint": {
                    #     "@type": "ContactPoint",
                    #     "telephone": "+44 20 5678 1234",
                    #     "contactType": "sales"
                    # }
                }
            })
        micro_data = {
            "@context": "https://schema.org",
            "@type": "ItemList",
            "itemListElement": item_list,
        }
        return micro_data


class DeveloperSort(graphene.Enum):
    NAME_ASC = "name"
    NAME_DESC = "-name"
    CREATED_AT_ASC = "created_at"
    CREATED_AT_DESC = "-created_at"
    RATING_ASC = "developer__rate"
    RATING_DESC = "-developer__rate"
    PROPERTY_NUM_ASC = "property_num"
    PROPERTY_NUM_DESC = "-property_num"
    RANDOM = "?"


class Query(graphene.ObjectType):
    developers = graphene.Field(FilterDeveloperType, page=graphene.Int(), page_size=graphene.Int(), search=graphene.String(
    ), featured=graphene.Boolean(), city=graphene.String(), country=graphene.String(), sort_by=DeveloperSort(), language=graphene.String())
    developer = graphene.Field(DeveloperTranslateType, slug=graphene.String(
        required=True), language=graphene.String())

    def resolve_developers(root, info, page=1, page_size=10, search=None, featured=None, city=None, country=None, sort_by=DeveloperSort.PROPERTY_NUM_DESC, language="en"):
        cache_key = f"developers_query_{page}_{page_size}_{search}_{featured}_{city}_{country}_{sort_by}_{language}"
        cached_result = cache.get(cache_key)
        if cached_result:
            return cached_result
        if page_size > 50:
            page_size = 50
        lang = Language.objects.filter(code=language).first()
        if lang is None:
            lang = Language.objects.filter(code="en").first()
        filters = Q(developer__is_active=True,
                    developer__is_deleted=False, language=lang)
        if featured is not None:
            filters &= Q(developer__is_featured=featured)
        if search is not None and search != "":
            filters &= Q(developer__name__icontains=search) | Q(
                developer__translates__name__icontains=search)
        if city is not None and city != "":
            filters &= Q(developer__city__slug=city)
        if country is not None and country != "":
            filters = Q(developer__country__slug=country)
        developments_prefetch = Prefetch(
            'developer__developments',
            queryset=Development.objects.filter(
                is_active=True, is_deleted=False)
        )
        qs = DeveloperTranslate.objects.select_related(
            'language',
            'developer',
            'developer__city',
            'developer__country'
        ).prefetch_related(
            developments_prefetch,
            'developer__translates'
        ).annotate(property_num=Count('developer__developments')).filter(filters).exclude(Q(developer__name=None) | Q(developer__name="")).order_by(sort_by.value)
        count = qs.count()
        pages_count = ceil(count / page_size)
        if page > pages_count:
            page = pages_count
        if page < 1:
            page = 1

        start = 0 + (page - 1) * page_size
        end = start + page_size
        has_next_page = end < count

        canonical_url = f"https://entralon.com/{lang.code}/developers"
        title = "Developers"
        description = "list of Developer on Entralon."
        qp = ""
        if search:
            qp += f"{'&' if qp != '' else ''}search={search}"
            title = f"search {search} in Developers"
            description = f"list of search {search} in Developer on Entralon."
        if featured:
            qp += f"{'&' if qp != '' else ''}is_featured=true"
            title += f" is featured"
            description += f"list of featured Developers on Entralon."
        if country:
            qp += f"{'&' if qp != '' else ''}country={country}"
            title += f" in {country} country"
            description += f"list of developer in {country} country on Entralon."
        if city:
            qp += f"{'&' if qp != '' else ''}city={city}"
            title += f" in {city} city"
            description += f"list of developer in {city} city on Entralon."
        if page > 1:
            qp += f"{'&' if qp != '' else ''}page={page}"
            title += f" | Page {page}"
            description += f" | Page {page}"
        if qp != "":
            qp = "?" + qp
        canonical_url += qp
        title += " | Entralon"
        image = f"https://file.entralon.com/{SiteSettings.objects.first().default_developer_image}"
        out = {
            "node": qs[start:end],
            "page_info": {
                "has_next_page": has_next_page,
                "has_previous_page": page > 1,
                "current_page": page,
                "page_size": page_size,
                "count": count,
                "pages_count": pages_count,
            },
            "meta_tags": {
                "title": title,
                "description": description,
                "keywords": "developer, entralon, building, builder, real estate",
                "og_title": title,
                "og_description": description,
                "og_image": image,
                "og_type": "website",
                "twitter_card": "summary",
                "twitter_title": title,
                "twitter_description": description,
                "twitter_image": image,
                "canonical_url": canonical_url
            }
        }
        cache.set(cache_key, out, CACHE_TIME)
        return out

    def resolve_developer(root, info, slug, language="en"):
        lang = Language.objects.filter(code=language).first()
        slug = slug.replace("developer-", "")
        if lang is None:
            lang = Language.objects.filter(code="en").first()
        developer = DeveloperTranslate.objects.filter(Q(developer__slug=slug) | Q(
            developer__translates__slug=slug), language=lang, developer__is_active=True, developer__is_deleted=False).first()
        if developer is None:
            developer = DeveloperTranslate.objects.select_related('language', 'developer').prefetch_related('developer__developments').filter(
                Q(developer__slug=slug) | Q(developer__translates__slug=slug), language__code="en", developer__is_active=True, developer__is_deleted=False).first()

        return developer


schema = graphene.Schema(query=Query)
