from collections import defaultdict

from fastapi import FastAPI, Depends, Path, Query
from fastapi.middleware.cors import CORSMiddleware
from typing import List, Annotated, Tuple, Literal
from sqlmodel import SQLModel, Session, select

from eveal.schemas import Evepraisal, PriceReprocess
from eveal.database import engine, get_session
from eveal import models_sde, esi

SQLModel.metadata.create_all(engine)  # use alembic?

app = FastAPI()
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])


@app.get("/")
async def root():
    return {"message": "Hello World"}


@app.post("/reprocess/")
async def reprocess(ep_items: Evepraisal, ep_mat: Evepraisal, efficiency: float = .55, db: Session = Depends(get_session)) -> List[PriceReprocess]:
    matprices = {item.typeID: {'sell': item.prices.sell.min, 'buy': item.prices.buy.max} for item in ep_mat.items}

    item_reprocess: List[PriceReprocess] = []
    for rawitem in ep_items.items:
        # item = sde.exec(select(models_sde.Type).where(models_sde.SDEType.id == rawitem.typeID)).one()
        item = db.get(models_sde.SDEType, rawitem.typeID)
        buy_reprocess = sell_reprocess = 0.0
        for mat in item.materials.all():
            buy_reprocess += matprices[mat.type.id]['buy'] * mat.quantity * efficiency
            sell_reprocess += matprices[mat.type.id]['sell'] * mat.quantity * efficiency
        item_reprocess.append(PriceReprocess(typeID=item.typeID,
                                             buy=item.prices.buy.max,
                                             sell=item.prices.sell.min,
                                             buy_reprocess=buy_reprocess,
                                             sell_reprocess=sell_reprocess,
                                             name=item.name
                                             ))
    return item_reprocess


@app.get("/sde/types/{sde_type}/")
async def sde_types(sde_type: int | str, db: Session = Depends(get_session)) -> models_sde.SDEType:
    try:
        item = db.get(models_sde.SDEType, int(sde_type))
    except ValueError:
        item = db.exec(select(models_sde.SDEType).where(models_sde.SDEType.name == sde_type)).one()
    return item


@app.post("/sde/types/search")
async def sde_types_search(query: List[Tuple[Literal["id", "name"], int | str]], db: Session = Depends(get_session)) -> List[models_sde.SDEType]:
    items = []
    for key, val in query:
        items.extend(db.exec(select(models_sde.SDEType).where(getattr(models_sde.SDEType, key) == val)).all())
    return items


@app.get("/esi/types/{sde_type}/market/{region_id}/")
async def sde_types_market(sde_type: int | str, region_id: int | str, db: Session = Depends(get_session)):
    """Get market orders for a type in a region. example: /esi/types/22291/market/10000002/"""
    """TODO: use ESIMarketOrder"""
    return list(esi.esi_client.Market.get_markets_region_id_orders(order_type="all", type_id=sde_type, region_id=region_id))


if __name__ == "__main__":
    import uvicorn
    uvicorn.run("eveal.main:app", host="0.0.0.0", port=8000, reload=True)
