#%%
import os
import pandas as pd
import geopandas as gpd
import numpy as np
import requests

def load_crop(base_path : str) -> gpd.GeoDataFrame:
    '''
    reads in crop.csv, assuming it is stored at $(base_path)/crops.csv
    Parameters
    --------------------------------
    input: base_path for a directory
    Outputs
    --------------------------------
    output: pd.Dataframe of crop
    '''

    crop = pd.read_csv(os.path.join(base_path, 'crop.csv'))
    crop['geometry'] = gpd.GeoSeries.from_wkt(crop['field_geometry'])
    crop = gpd.GeoDataFrame(crop)

    return crop

def load_weather(base_path : str) -> pd.DataFrame:
    '''
    reads in weather.csv, assuming it is stored at $(base_path)/spectral.csv,
    Parameters
    --------------------------------
    input: base_path for a directory
    Outputs
    --------------------------------
    output: pd.Dataframe of weather, gpd.Dataframe of fields
    '''

    weather = pd.read_csv(os.path.join(base_path, 'weather.csv'), dtype= {'fips_code' : object})
    fields = load_crop(base_path)

    return weather, fields

def lookup_fips(lat, lon):
    '''
    looks up lat lon --> fips code
    Parameters
    --------------
    lat
    lon
    Outputs
    ------------
    fips

    '''
    url = 'https://geo.fcc.gov/api/census/block/find?latitude=%s&longitude=%s&format=json' % (lat, lon)
    response = requests.get(url)
    data = response.json()
    state = data['State']['FIPS']
    county = data['County']['FIPS'][2:]
    return str(state) + str(county)

#%%
def transform_weather(weather : pd.DataFrame, fields : gpd.GeoDataFrame) -> pd.DataFrame:
    '''
    takes in weather and fields, geocodes fields

    Parameters
    ----------
    Weather
    Fields
    --------
    Output
    Fields with weather data
    '''
    fields = fields[['field_id', 'geometry']].drop_duplicates()
    weather = weather[weather['year']==2021]
    weather = (weather
        .groupby('fips_code', as_index=False)
        .agg(precip = ('precip', 'sum'),
         max_temp = ('temp', 'max'),
         mean_temp = ('temp', 'mean'))
    )
    fields["lon"] = fields.centroid.x
    fields["lat"] = fields.centroid.y
    fields['fips_code'] = fields.apply(lambda x: lookup_fips(x.lat, x.lon), axis =1)

    joined_fields = fields[['field_id', 'fips_code']].merge(weather, left_on = 'fips_code', right_on = 'fips_code')
    return joined_fields

def write_weather(weather : pd.DataFrame, output_path : str) -> None:
    '''
    writes processed soil to $(output_path)/spectral.csv
    '''
    weather.to_csv(os.path.join(output_path, 'weather.csv'))

# %%

def process_weather(base_path : str, output_path : str) -> None:
    weather, fields = load_weather(base_path)
    weather = transform_weather(weather, fields)
    write_weather(weather, output_path)


import os
from pages.page_manager import PageManager
from json import dumps, load
from pages.page import get_path_data, get_post_data, get_user_from_event
from utils.utils import ses_client, lambda_constants, get_response_from_cache_response, get_method_from_event, get_path_from_event, respond, redirect
from time import time
import traceback

last_cache_clear = time()
page_manager = PageManager()

def get_page_from_event(event, method):
    if "rawPath" in event:
        try:
            route = event["rawPath"].split("/")[1]
            if method == "GET":
                if route == "":
                    return page_manager.pages_get["home"]
                elif route in page_manager.pages_get:
                    return page_manager.pages_get[route]
            elif method == "POST":
                if route == "":
                    return page_manager.pages_get["home"]
                elif route in page_manager.pages_post:
                    return page_manager.pages_post[route]
            return None
        except:
            return None
    return None

def lambda_handler(event, context):
    try:
        return main_lambda_handler(event, context)
    except Exception as e:
        send_error_email(event, e)
        path = get_path_data(get_path_from_event(event), event)
        post = {}
        return respond(page_manager.pages_get["not_found"].get(event, path, post, "infelizmente um erro aconteceu, já enviamos um relatório para o suporte e brevemente ele será solucionado", None), event)

def main_lambda_handler(event, context):
    method = get_method_from_event(event)
    if method != "GET" and method != "POST":
        return respond("", event)
    if method == "GET":
        response_from_cache = get_response_from_cache_response(event)
        if response_from_cache:
            return response_from_cache

    page = get_page_from_event(event, method)
    ### SHOW PAGE IN INVOKER ###
    if page:
        print(dumps(method) + " -> " + str(dumps(page.route)) + " -> " + dumps(event))
    user = get_user_from_event(event)

    ### CLEAR CACHES ###
    # global last_cache_clear
    # if time() > (last_cache_clear + 10):
    #     clear_caches()

    # ### REDIRECT TO ANOTHER LAMBDAS ###
    # if page is None:
    #     project = get_second_param_in_raw_path(event)
    #     if project:
    #         print(dumps(method) + " -> " + dumps(project) + " -> " + dumps(event))
    #         if project == "get_queue_position":
    #             return lambda_get_queue_position(event, user)
    #         if project == "get_reception_queue":
    #             return lambda_get_reception_queue(event, user)

    path = get_path_data(get_path_from_event(event), event)
    post = {}

    if "ERROR" in path:
        return respond(page_manager.pages_get["not_found"].get(event, path, post, path["ERROR"], user), event)
    if not user and not page.public:
        return respond(redirect("login/must_be_logged_in"), event)
    if user and page.bypass:
        return respond(redirect(""), event)
    if method == "GET":
        return respond(page.get(event, path, post, None, user), event)
    if method == "POST":
        post = get_post_data(event, post)
        return respond(page.post(event, path, post, None, user), event)

def send_error_email(event, e):
    tb = traceback.format_exc()
    html = "LAMBDA ERROR IN PETMAPA: " + str(e) + "\n\n

 TRACEBACK: " + tb + "\n\n

 EVENT: " + dumps(event)
    ses_client.send_email(
        Destination={"ToAddresses": ["eugenio@devesch.com.br"]},
        Message={
            "Body": {
                "Html": {
                    "Charset": "utf-8",
                    "Data": str(html),
                },
                "Text": {
                    "Charset": "utf-8",
                    "Data": str(html),
                },
            },
            "Subject": {
                "Charset": "utf-8",
                "Data": "LAMBDA ERROR IN PETMAPA",
            },
        },
        Source="eugenio@devesch.com.br",
        ConfigurationSetName=lambda_constants["domain_name"],
    )
    return

if os.environ.get("AWS_EXECUTION_ENV") is None:
    with open("_testnow.json", "r") as read_file:
        event = load(read_file)
        html = main_lambda_handler(event, None)
    f = open("test_html.html", "w")
    f.write(html.get("body"))
    f.close()
    import webbrowser

    webbrowser.open("file://" + os.path.realpath(os.getcwd() + "/test_html.html"))
    print("END")


import numpy as np
from lzcompression.types import FloatArrayType

def construct_utility(
    low_rank_matrix: FloatArrayType, base_matrix: FloatArrayType
) -> FloatArrayType:
    """Construct a utility matrix Z which enforces the invariants of the original
    sparse nonnegative matrix.

    Specifically, it creates Z from a 0-matrix by:
      - Copying the positive elements of the original sparse matrix X into the
        corresponding elements of Z
      - Copying any negative elements of the current low-rank approximation matrix
        L into the corresponding elements of Z, provided those elements of Z
        were not set in the first step
      - Any remaining elements remain 0

    i.e. for each i, j: Z_ij = X is X_ij > 0, else min(0, L_ij).

    Args:
        low_rank_matrix: The current low-rank approximation of the base matrix
        base_matrix: the sparse nonnegative matrix whose low-rank approximation
            is being sought

    Returns:
        A utility matrix whose only positive values are the positive values in
        the base_matrix
    """
    conditions = [base_matrix > 0, low_rank_matrix < 0]
    choices = [base_matrix, low_rank_matrix]
    utility_matrix = np.select(conditions, choices, 0)
    return utility_matrix


import pygame

pygame.init()

# 创建游戏的窗口
screen = pygame.display.set_mode((480, 700))

# 绘制背景图像
background = pygame.image.load("./images/background.png")
screen.blit(background, (0, 0))
# pygame.display.update()

# 绘制英雄的飞机
hero = pygame.image.load("./images/me1.png")
screen.blit(hero, (200, 500))

# 可以再所有绘制工作完成后，统一调用update方法
pygame.display.update()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()

pygame.quit()