from django import forms
from django.conf import settings
from django.template.defaultfilters import filesizeformat
from mapbox_location_field.forms import LocationField
from django.utils import timezone

from purchase.TimeInputCool import TimeInputCool
from shop import models
from localflavor.es.forms import ESIdentityCardNumberField
from shop.range import RangeSliderField
from shop.select_category import SelectCategoryField

class ShopForm(forms.ModelForm):

    def clean_photo(self):
        photo = self.cleaned_data['photo']
        if photo is None:
            raise forms.ValidationError("Siusplau, afegeix una fotografia")
        size = getattr(photo, '_size', 0)
        if size > settings.MAX_UPLOAD_SIZE:
            raise forms.ValidationError("Siusplau, la foto ha de tenir un tamany inferior a %s. Actualment %s" % (
                filesizeformat(settings.MAX_UPLOAD_SIZE), filesizeformat(size)))
        return photo

    CIF = ESIdentityCardNumberField(only_nif=False, label='', widget=forms.TextInput(attrs={'placeholder': 'CIF'}))
    secondaryCategories = SelectCategoryField(queryset=models.SecondaryCategory.objects.all(),
                                              placeholder='Busca una categoria ...', is_loading=False,
                                              title="Filtra per categoria:")
    services = SelectCategoryField(queryset=models.Service.objects.all(),
                                   placeholder='Busca un servei ...', is_loading=False, title="Filtra per servei:",
                                   required=False)

    meanTime = RangeSliderField(label="", minimum=0, maximum=60, step=5,
                                name="Quant temps passen els teus usuaris de mitjana?")

    map = LocationField(label='Mapa', map_attrs={"center": [2.1589899, 41.3887901], "marker_color": "#ba6b6c",
                                                 'zoom': 10, 'placeholder': 'Tria una localització a sota'})

    class Meta:
        model = models.Shop
        fields = ['CIF', 'name', 'description', 'meanTime', 'services', 'secondaryCategories', 'photo']

        labels = {
            'name': '',
            'description': '',
            'photo': 'Foto'
        }

        help_text = {
            'CIF': 'CIF',
            'name': 'Name',

        }

        exclude = ['latitude', 'longitude']

        widgets = {
            'name': forms.TextInput(attrs={'placeholder': 'Nom de la botiga'}),
            'description': forms.Textarea(attrs={'rows': 4, 'placeholder': 'Descripció'}),
            'photo': forms.FileInput(),
        }

    def clean(self):
        map = self.cleaned_data['map']
        if map is None:
            raise forms.ValidationError("Necesites unes coordenades")
        elif float(map.split(',')[0]) <= -180 or float(map.split(',')[0]) >= 180:
            raise forms.ValidationError("Longitude fora de rang")
        elif float(map.split(',')[1]) < -90 or float(map.split(',')[1]) >= 90:
            raise forms.ValidationError("Latitude fora de rang")
        else:
            pass
        return self.cleaned_data

    def is_add_shop(self):
        return True

class ScheduleForm(forms.ModelForm):
    startHour = forms.TimeField(required=True, label='Començament de la jornada',
                                initial='%02d:%02d' % (timezone.now().hour, timezone.now().minute),
                                widget=TimeInputCool())
    endHour = forms.TimeField(required=True, label='Fi de la jornada',
                              initial='%02d:%02d' % (timezone.now().hour, timezone.now().minute),
                              widget=TimeInputCool())

    class Meta:
        model = models.Schedule
        fields = ['day', 'startHour', 'endHour']
        exclude = ['shop']
        labels = {
            'day': 'Dia'
        }

    def clean(self):
        self.cleaned_data['day']
        startHour = self.cleaned_data['startHour']
        endHour = self.cleaned_data['endHour']
        if startHour > endHour:
            raise forms.ValidationError('L\'hora d\'inici no pot ser més gran que la hora final')
        return self.cleaned_data

class AddShopAdminForm(forms.Form):
    email = forms.EmailField(required=True, label='',
                             widget=forms.EmailInput(attrs={'placeholder': 'Correu electrònic'}))


"""
This module provides the `gdaps_settings` object, that is used to access
GDAPS settings, checking for user settings first, then falling
back to the defaults.
"""
import os
from importlib import import_module

from django.conf import settings
from django.test.signals import setting_changed

# Copied shamelessly from Graphene-Django, with little adaptions

NAMESPACE = "GDAPS"

DEFAULTS = {"ADMIN": True}

# List of settings that may be in string import notation.
IMPORT_STRINGS = []

# List of settings that have been removed
REMOVED_SETTINGS = ()

def perform_import(val, setting_name):
    """
    If the given setting is a string import notation,
    then perform the necessary import or imports.
    """
    if val is None:
        return None
    elif isinstance(val, str):
        return import_from_string(val, setting_name)
    elif isinstance(val, (list, tuple)):
        return [import_from_string(item, setting_name) for item in val]
    return val

def import_from_string(val, setting_name):
    """
    Attempt to import a class from a string representation.
    """
    try:
        # Nod to tastypie's use of importlib.
        parts = val.split(".")
        module_path, class_name = ".".join(parts[:-1]), parts[-1]
        module = import_module(module_path)
        return getattr(module, class_name)
    except (ImportError, AttributeError) as e:
        msg = f"Could not import '{val}' for plugin setting '{setting_name}'.{e.__class__.__name__}: {e}."
        raise ImportError(msg)

class PluginSettings:
    """
    A settings object, that allows app specific settings to be accessed as properties.
    For example:
        settings.py:
            GDAPS = { "FOO_SETTING": "blah" }

        anywhere else:
            from gdaps.conf import gdaps_settings
            print(gdaps_settings.FOO_SETTING)

    Any setting with string import paths will be automatically resolved
    and return the class, rather than the string literal.
    """

    def __init__(
        self,
        namespace: str = None,
        user_settings: list = None,
        defaults: dict = None,
        import_strings=None,
        removed_settings=None,
    ):

        if user_settings:
            self._user_settings = user_settings
        self.defaults = defaults or DEFAULTS
        self.import_strings = import_strings or IMPORT_STRINGS
        self.removed_settings = removed_settings or REMOVED_SETTINGS

        if not namespace == namespace.upper():
            raise RuntimeError("Django settings must be UPPERCASE.")
        self._namespace = namespace or NAMESPACE

        setting_changed.connect(self.reload)

    @property
    def user_settings(self):
        if not hasattr(self, "_user_settings"):
            self._user_settings = getattr(settings, self._namespace, {})
        return self._user_settings

    def __getattr__(self, attr):
        if attr in self.removed_settings:
            raise AttributeError(
                f"Invalid plugin settings attribute: '{self._namespace}' has invalid (removed) key '{attr}'."
            )
        if attr not in self.defaults:
            raise AttributeError(
                f"Invalid plugin settings attribute: '{self._namespace}' doesn't allow key '{attr}'"
            )

        try:
            # Check if present in user settings
            val = self.user_settings[attr]
        except KeyError:
            # Fall back to defaults
            val = self.defaults[attr]

        # Coerce import strings into classes
        if attr in self.import_strings:
            val = perform_import(val, attr)

        setattr(self, attr, val)
        return val

    @staticmethod
    def reload(*args, **kwargs):
        # FIXME: this does not work for inherited pluginsettings of other modules...! it's hardcoded "gdaps_settings".
        global gdaps_settings
        setting, value = kwargs["setting"], kwargs["value"]
        if setting == NAMESPACE:
            gdaps_settings = PluginSettings(NAMESPACE, value, DEFAULTS, IMPORT_STRINGS)

gdaps_settings = PluginSettings(NAMESPACE, None, DEFAULTS, IMPORT_STRINGS)


from shapely.geometry import shape
from shapely.ops import unary_union
import geopandas as gpd
import os
from tqdm import tqdm
from utils import load_processed_data

import warnings
warnings.filterwarnings('ignore')

"""
    1:1 = OSi footprint matches exactly one OSM footprint
    1:0 = OSi footprint not matches with any OSM footprint
    1:many = osi footprint matches with more than one osm footprint
    many:1 = more than one OSi footprints match with one OSM footprint
    many: many  = more than one OSi footprints match with more than one OSM footprints
"""

def calculate_completeness(osi, osm):
    relationships = {}
    osm_relationships = {}
    # Count the number of intersections
    for osi_geojson in tqdm(osi, total=len(osi), desc="Calculating completeness"):
        osi_filename = os.path.basename(osi_geojson)
        relationships[osi_filename] = []
        osi_geojson = gpd.read_file(osi_geojson)
        osi_shape = shape(osi_geojson.geometry.iloc[0])
        for osm_geojson in osm:
            osm_filename = os.path.basename(osm_geojson)
            osm_geojson = gpd.read_file(osm_geojson)
            osm_shape = shape(osm_geojson.geometry.iloc[0])
            if osi_shape.intersects(osm_shape):
                relationships[osi_filename].append(osm_filename)
                osm_relationships.setdefault(osm_filename, []).append(osi_filename)

    completeness_1_1 = 0
    completeness_1_0 = 0
    completeness_1_many = 0
    completeness_many_1 = 0
    completeness_many_many = 0

    # Calculate completeness metrics based on the relationships
    for osi_filename, osm_filenames in relationships.items():
        num_osm_files = len(osm_filenames)

        if num_osm_files == 1:
            completeness_1_1 += 1
        elif num_osm_files == 0:
            completeness_1_0 += 1
        elif num_osm_files > 1:
            completeness_1_many += 1

    for osm_filename, osi_filenames in osm_relationships.items():
        num_osi_files = len(osi_filenames)

        if num_osi_files == 1:
            completeness_many_1 += 1
        elif num_osi_files > 1:
            completeness_many_many += 1

    total_files = len(osi) + len(osm)

    # Calculate the completeness percentages
    completeness_1_1 = (completeness_1_1 / total_files) * 100
    completeness_1_0 = (completeness_1_0 / total_files) * 100
    completeness_1_many = (completeness_1_many / total_files) * 100
    completeness_many_1 = (completeness_many_1 / total_files) * 100
    completeness_many_many = (completeness_many_many / total_files) * 100

    return {
        "1:1": completeness_1_1,
        "1:0": completeness_1_0,
        "1:many": completeness_1_many,
        "many:1": completeness_many_1,
        "many:many": completeness_many_many
    }

samples = load_processed_data("processed_data")
all_osi = [i[0] for i in samples]
all_osm = [i[1] for i in samples]
all_pred = [i[2] for i in samples]

completeness = calculate_completeness(all_osi, all_pred)
print("Completeness based on overlap:")
print("1:1 =", completeness['1:1'])
print("1:0 =", completeness['1:0'])
print("1:many =", completeness['1:many'])
print("many:1 =", completeness['many:1'])
print("many:many =", completeness['many:many'])

print(completeness)

# plot bar chart
import matplotlib.pyplot as plt
import numpy as np

labels = ['1:1', '1:0', '1:many', 'many:1', 'many:many']
values = [completeness['1:1'], completeness['1:0'], completeness['1:many'], completeness['many:1'], completeness['many:many']]
x = np.arange(len(labels))  # the label locations
width = 0.35  # the width of the bars
plt.figure(figsize=(10, 5))
plt.bar(x, values, width, label='Completeness')
plt.xticks(x, labels)
# use percentage to 100
plt.yticks(np.arange(0, 101, 10))
plt.ylabel('Percentage')
plt.xlabel('Relationship')
plt.title('Completeness based on overlap')
plt.legend()
plt.show()


from setuptools import find_packages,setup
from typing import List

def get_requirements(file_path:str)->List[str]:
    requirements=[]
    with open(file_path) as file_obj:
        requirements=file_obj.readlines()
        requirements=[req.replace("\n","") for req in requirements]

        return requirements

setup(
    name='Diamond_Price_prediction',
    version='0.0.1',
    author='hemangi',
    author_email='vagahsiya295@gmail.com',
    install_requies=get_requirements('requirement.txt'),
    packages=find_packages()
)


import asyncio

import aiohttp

async def fetch(session, url):
    print("发送请求：", url)
    async with session.get(url, verify_ssl=False) as response:
        text = await response.text()
        print("得到结果：", url, len(text))
        return text

async def main():
    async with aiohttp.ClientSession() as session:
        utl_list = [
            'https://www.baidu.com',
            'https://www.qq.com',
            'https://www.163.com'
        ]
        tasks = [asyncio.create_task(fetch(session, url)) for url in utl_list]
        done, pending = await asyncio.wait(tasks)

if __name__ == '__main__':
    asyncio.run(main())


from django.urls import path, re_path, include
from . import views

app_name = "main_app"

urlpatterns = [
    re_path(r'^$', views.main_page, name="main_page"),
    path('product<int:pk>', views.product, name="product"),
    path('category', views.category_main, name="category_main"),
    path('category/<int:pk>', views.category, name="category"),
]