import asyncio
from datetime import datetime
import logging

from aiohttp import ClientSession
from dateutil.parser import parse

from zet import api, config, database
from zet.http import make_session
from zet.utils import iterate_pairs

logger = logging.getLogger(__name__)


async def load_map_lines_cached(max_days=30):
    conn = database.get_conn()
    cursor = conn.execute("SELECT * FROM meta")
    meta = cursor.fetchone()
    conn.commit()

    imported_at = meta["map_lines_imported_at"]
    imported_at = parse(imported_at) if imported_at else datetime.min
    days_since = (datetime.now() - imported_at).days

    if days_since > max_days:
        logger.debug(f"map_lines loaded {days_since} days ago, updating")
        await load_map_lines()
    else:
        logger.debug(f"map_lines loaded {days_since} days ago, no need to update")


async def load_map_lines():
    conn = database.get_conn()
    conn.execute("DELETE FROM map_lines;")

    logger.info("Loading shapes...")
    async with make_session() as session:
        response = await api.get_shapes(session)
        shapes = response.json()

    logger.info(f"Processing {len(shapes)} shapes...")
    values = set()
    for name, points in shapes.items():
        for p1, p2 in iterate_pairs(points):
            values.add((p1["latitude"], p1["longitude"], p2["latitude"], p2["longitude"]))

    cursor = conn.executemany(
        "INSERT INTO map_lines(lat1, lon1, lat2, lon2) VALUES (?, ?, ?, ?)", values
    )
    logger.info(f"Imported {cursor.rowcount} map lines")
    conn.execute("UPDATE meta SET map_lines_imported_at = datetime('now')")
    conn.commit()


async def load_routes(session: ClientSession):
    logger.info("Loading routes...")

    path = _routes_path()
    response = await api.get_routes(session)
    with open(path, "w") as f:
        f.write(response.body)

    logger.info(f"Routes saved to {path}")


async def load_shapes(session: ClientSession):
    logger.info("Loading shapes...")

    path = _shapes_path()
    response = await api.get_shapes(session)
    with open(path, "w") as f:
        f.write(response.body)

    logger.info(f"Shapes saved to {path}")


async def load_stops(session: ClientSession):
    logger.info("Loading stops...")

    path = _stops_path()
    response = await api.get_stops(session)
    with open(path, "w") as f:
        f.write(response.body)

    logger.info(f"Stops saved to {path}")


async def load_all(session: ClientSession):
    asyncio.gather(
        load_routes(session),
        load_shapes(session),
        load_stops(session),
    )


def _routes_path():
    return config.get_cache_dir() / "routes.json"


def _shapes_path():
    return config.get_cache_dir() / "shapes.json"


def _stops_path():
    return config.get_cache_dir() / "stops.json"


async def _main():
    async with make_session() as session:
        await load_routes(session)
        await load_shapes(session)
        await load_stops(session)


if __name__ == "__main__":
    logging.basicConfig(level=logging.DEBUG)
    asyncio.run(load_map_lines_if_needed())
