import datetime
import json

import requests
from data_scraper.utils import translate_text_by_google
from geo_location.utils import GeoLocation
from django.utils.text import slugify
from .models import City, CityTranslate, Country, CountryTranslate, District, Iso31662, Location, LocationTranslate, LondonArea, LondonZipState, LondonZone, PostCode, State
from main.models import Language
from django.db.models import Q
import textwrap

def translate_country():
    languages = Language.objects.exclude(code="en")
    base_language = Language.objects.get(code="en")
    for country in Country.objects.filter(translated=False)[:10]:
        try: l = country.translates.get(language=base_language)
        except: l = CountryTranslate.objects.create(country=country, language=base_language, name=country.name, slug=country.slug)
        if l is not None:
            try:
                name = l.name
                slug = l.slug
                description = l.description
                for language in languages:
                    t_name = None
                    t_slug = None
                    t_description = None
                    if name is not None: t_name = translate_text_by_google(name, to_language=language.code)
                    if slug is not None: t_slug = translate_text_by_google(slug, to_language=language.code)
                    if description is not None and description != "":
                        lines = []
                        try: lines = textwrap.wrap(description, 300, break_long_words=False)
                        except Exception as e: print("description", e)
                        des = []
                        for line in lines:
                            if line is not None: des.append(translate_text_by_google(line, to_language=language.code))
                        t_description = " ".join(des)
                    
                    
                    try: 
                        try: country_t = CountryTranslate.objects.get(language=language, country=country)
                        except: country_t = CountryTranslate(language=language, country=country)
                        country_t.name=t_name
                        country_t.slug=t_slug
                        country_t.description=t_description
                        country_t.save()
                        
                    except Exception as e: print(e)
                
                country.translated = True
                country.save()
            except Exception as e: print(e)
                
def translate_city():
    languages = Language.objects.exclude(code="en")
    base_language = Language.objects.get(code="en")
    for city in City.objects.filter(translated=False)[:10]:
        try: l = city.translates.get(language=base_language)
        except: l = CityTranslate.objects.create(city=city, language=base_language, name=city.name, slug=city.slug)
        if l is not None:
            try:
                name = l.name
                slug = l.slug
                description = l.description
                for language in languages:
                    t_name = None
                    t_slug = None
                    t_description = None
                    if name is not None: t_name = translate_text_by_google(name, to_language=language.code)
                    if slug is not None: t_slug = translate_text_by_google(slug, to_language=language.code)
                    if description is not None and description != "":
                        lines = []
                        try: lines = textwrap.wrap(description, 300, break_long_words=False)
                        except Exception as e: print("description", e)
                        des = []
                        for line in lines:
                            if line is not None: des.append(translate_text_by_google(line, to_language=language.code))
                        t_description = " ".join(des)
                    
                    
                    try: 
                        try: city_t = CityTranslate.objects.get(language=language, city=city)
                        except: city_t = CityTranslate(language=language, city=city)
                        city_t.name=t_name
                        city_t.slug=t_slug
                        city_t.description=t_description
                        city_t.save()
                        
                    except Exception as e: print(e)
                
                city.translated = True
                city.save()
            except Exception as e: print(e)
            
def get_location_raw():
    locations = Location.objects.filter(raw__isnull=True)[:10]
    geo_location = GeoLocation()
    for location in locations:
        for language in Language.objects.all():
            try:
                gl = geo_location.get_address(location.coordinates.y, location.coordinates.x, language.code)
                if gl is not None:
                    lt, _ = LocationTranslate.objects.get_or_create(location=location, language=language)
                    lt.address = gl.address
                    lt.raw = gl.raw
                    lt.save()
                    if language.code == "en":
                        location.raw = gl.raw
                        location.address = gl.address
                        location.save()
                else:
                    print(f'on {datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")} location address for [{location.name}:{location.id}] not found.')
            except Exception as e: print(f'on {datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")} location address for [{location.name}:{location.id}] error: {e}.')
            
def set_location_data():
    locations = Location.objects.filter(raw__isnull=False, raw_check=False)[:20]
    
    for location in locations:
        gl = location.raw
        if location.name is None and gl.get('name') is not None: 
            location.name = gl.get('name')
            location.slug = slugify(gl.get('name'), allow_unicode=True)
        if location.point_type is None or location.point_type != gl.get('type') and gl.get('type') is not None: 
            location.point_type = gl.get('type')
        if location.point_class is None or location.point_class != gl.get('class') and gl.get('class') is not None: 
            location.point_class = gl.get('class')
        address_dict = gl.get('address')
        if address_dict is not None:
            country_name = address_dict.get('country')
            country_slug = slugify(country_name, allow_unicode=True)
            country_code = address_dict.get('country_code')
            country = None
            if country_name is not None:
                country = Country.objects.filter(Q(slug=country_slug) | Q(translates__slug=country_slug)).first()
                if country is None:
                    country = Country.objects.create(name=country_name, slug=country_slug, code=country_code)
            elif country_code is not None: 
                country_code = country_code.lower()
                country = Country.objects.filter(code=country_code).first()
                if country is None:
                    country = Country.objects.create(name=country_name, slug=country_slug, code=country_code)
            
            city = None
            city_name = address_dict.get('city')
            if city_name is not None:
                city_slug = slugify(city_name, allow_unicode=True)
                city = City.objects.filter(Q(slug=city_slug) | Q(translates__slug=city_slug)).first()
                if city is None:
                    city = City.objects.create(name=city_name, slug=city_slug)
            state = None
            state_name = address_dict.get('state')
            if state_name is not None:
                state_slug = slugify(state_name, allow_unicode=True)
                state = State.objects.filter(Q(slug=state_slug) | Q(translates__slug=state_slug)).first()
                if state is None:
                    state = State.objects.create(name=state_name, slug=state_slug)
            if country is not None:
                location.country = country
                if city is not None:
                    city.country = country
                    city.save()
                if state is not None:
                    state.country = country
                    state.save()
            if city is not None:
                location.city = city
            if state is not None:
                location.state = state
            postcode = address_dict.get('postcode')
            if postcode is not None:
                location.zip_code = postcode
        rank = gl.get('place_rank')    
        if rank is not None:
            location.rank = rank
        display_name = gl.get('display_name')    
        if display_name is not None:
            location.display_name = display_name
        address_type = gl.get('addresstype')
        if address_type is not None:
            location.address_type = address_type
        place_id = gl.get('place_id')
        if place_id is not None:
            location.place_id = place_id
        location.raw_check = True    
        location.save()

def set_location_translate_data():
    locations = LocationTranslate.objects.filter(raw__isnull=False, raw_check=False)[:20]
    
    for location in locations:
        gl = location.raw
        if location.name is None and gl.get('name') is not None: 
            location.name = gl.get('name')
            location.slug = slugify(gl.get('name'), allow_unicode=True)
        display_name = gl.get('display_name')    
        if display_name is not None:
            location.display_name = display_name
        address_dict = gl.get('address')
        if address_dict is not None:
            building = address_dict.get('building')
            if building is not None:
                location.building = building
            street = address_dict.get('street')
            if street is not None:
                location.street = street
            else:
                road = address_dict.get('road')
                if road is not None:
                    location.street = road
            postcode = address_dict.get('postcode')
            if postcode is not None:
                location.zip_code = postcode
        place_id = gl.get('place_id')
        if place_id is not None:
            location.place_id = place_id
        location.raw_check = True    
        location.save()

            
def get_country_data():
    countries = Country.objects.filter(data__isnull=True, data_check=False)
    for country in countries:
        url = f"https://nominatim.openstreetmap.org/search?q={country.code}&format=json&polygon_geojson=1"
        try:
            req = requests.get(url, timeout=30)
            if req.status_code == 200:
                data = req.json()
                if data:
                    for item in data:
                        if item.get('addresstype') == 'country':
                            country.data = item
                            country.save()
            else:
                print(f'on {datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")} country data for [{country.name}:{country.id}] status code: {req.status_code}')
        except Exception as e:
            print(f'on {datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")} country data for [{country.name}:{country.id}] error: {e}')
                        
def set_country_coordinates():
    from django.contrib.gis.geos import GEOSGeometry, Polygon, MultiPolygon
    countries = Country.objects.filter(data__isnull=False, data_check=False)
    for country in countries:
        data = country.data
        if data is not None:
            geom_str = json.dumps(data['geojson'])
            geom = GEOSGeometry(geom_str)
            try:
                if isinstance(geom, MultiPolygon):
                    pass
                elif isinstance(geom, Polygon):
                    geom = MultiPolygon([geom])
                else:
                    raise TypeError(
                        '{} not acceptable for this model'.format(geom.geom_type)
                    )
                
                country.coordinates = geom
                country.data_check = True
                country.data = None
                country.save()
                
            except TypeError as e:
                print(e)
        
        
def get_city_data():
    cities = City.objects.filter(data__isnull=True, data_check=False)[:10]
    for city in cities:
        try: country_code = f",{city.country.slug}"
        except:country_code = ""
        url = f"https://nominatim.openstreetmap.org/search?q={city.slug}{country_code}&format=json&polygon_geojson=1"
        req = requests.get(url, timeout=30)
        if req.status_code == 200:
            data = req.json()
            if data:
                for item in data:
                    if item.get('addresstype') in ['city', 'suburb'] and item.get('geojson') is not None and item.get('geojson')['type'] in ['Polygon', 'MultiPolygon']:
                        print(city.slug, "ok")
                        city.data = item
                        city.save()
        else:
            print(f'on {datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")} city data for [{city.name}:{city.id}] status code: {req.status_code}')        
            
def set_city_coordinates():
    from django.contrib.gis.geos import GEOSGeometry, Polygon, MultiPolygon
    cities = City.objects.filter(data__isnull=False, data_check=False)
    for city in cities:
        print(city.name)
        data = city.data
        if data is not None:
            geom_str = json.dumps(data['geojson'])
            geom = GEOSGeometry(geom_str)
            try:
                if isinstance(geom, MultiPolygon):
                    pass
                elif isinstance(geom, Polygon):
                    geom = MultiPolygon([geom])
                else:
                    continue
                
                city.coordinates = geom
                city.data_check = True
                city.data = None
                city.save()
                
            except TypeError as e:
                print(e)
                

def location_info():
    
    for iso in Iso31662.objects.filter(coordinates__isnull=False):
        i = iso.level
        locations = Location.objects.filter(coordinates__intersects=iso.coordinates)
        if i == 0:
            locations.update(iso_3166_2_lvl_0=iso)
        elif i == 1:
            locations.update(iso_3166_2_lvl_1=iso)
        elif i == 2:
            locations.update(iso_3166_2_lvl_2=iso)
        elif i == 3:
            locations.update(iso_3166_2_lvl_3=iso)
        elif i == 4:
            locations.update(iso_3166_2_lvl_4=iso)
    for obj in Country.objects.all():
        if obj.coordinates is not None: Location.objects.filter(coordinates__intersects=obj.coordinates).update(country=obj)
    for obj in City.objects.all():
        if obj.coordinates is not None: Location.objects.filter(coordinates__intersects=obj.coordinates).update(city=obj)
    for obj in District.objects.all():
        if obj.coordinates is not None: Location.objects.filter(coordinates__intersects=obj.coordinates).update(district=obj)
    for obj in LondonZipState.objects.all():
        if obj.coordinates is not None: Location.objects.filter(coordinates__intersects=obj.coordinates).update(london_zip_state=obj)
    for obj in LondonArea.objects.all():
        if obj.coordinates is not None: Location.objects.filter(coordinates__intersects=obj.coordinates).update(london_area=obj)
    for obj in LondonZone.objects.all():
        if obj.coordinates is not None: Location.objects.filter(coordinates__intersects=obj.coordinates).update(london_zone=obj)
    for obj in LondonZipState.objects.all():
        if obj.coordinates is not None: 
            Location.objects.filter(coordinates__intersects=obj.coordinates).update(london_zip_state=obj)
            try:
                ps = PostCode.objects.get(out_code=obj.name)
                Location.objects.filter(coordinates__intersects=obj.coordinates).update(post_code=ps)
            except: pass
    


