from __future__ import annotations
from typing import Optional, Tuple, Any, List

import requests
import pandas as pd
import numpy as np
import asyncio
import aiohttp

GeoTupleType = Tuple[Optional[int], Optional[float], Optional[float]]


def get_building_id(street: str) -> GeoTupleType:
    if pd.isnull(street):
        return None, None, None

    r = requests.get('https://geocode.gate.petersburg.ru/parse/eas', params={
        'street': street
    }, timeout=10)

    res = r.json()

    if 'error' in res:
        return None, None, None

    return res['Building_ID'], res['Latitude'], res['Longitude']


def fetch_builing_ids(df: pd.DataFrame) -> pd.DataFrame:
    df[['ID здания', 'Широта', 'Долгота']] = df.apply(
        lambda row: get_building_id(row['Улица']), axis=1, result_type='expand')

    return df


async def async_fetch_building_id(session: aiohttp.ClientSession, street: str) -> GeoTupleType:
    if pd.isnull(street):
        return None, None, None

    async with session.get('https://geocode.gate.petersburg.ru/parse/eas', params={
        'street': street
    }) as r:
        res = await r.json()

        if 'error' in res:
            return None, None, None

        return res['Building_ID'], res['Latitude'], res['Longitude']


async def async_fetch_building_ids(df: pd.DataFrame) -> pd.DataFrame:
    async with aiohttp.ClientSession() as session:
        tasks = []

        for _, row in df.iterrows():
            tasks.append(
                asyncio.ensure_future(
                    async_fetch_building_id(session, row['Улица'])
                )
            )

        res = await asyncio.gather(*tasks)

        df[['ID здания', 'Широта', 'Долгота']] = res

        return df


def concurrent_fetch_builing_ids(df: pd.Dataframe) -> pd.DataFrame:
    return asyncio.run(
        async_fetch_building_ids(df)
    )