from fastapi import APIRouter, Request
from typing import Any, List, Dict, Union
from app.services.tjnetwork import (
    Any,
    ChangeSet,
    add_district_metering_area,
    add_region,
    add_service_area,
    add_virtual_district,
    calculate_district_metering_area_for_network,
    calculate_district_metering_area_for_nodes,
    calculate_district_metering_area_for_region,
    calculate_service_area,
    calculate_virtual_district,
    delete_district_metering_area,
    delete_region,
    delete_service_area,
    delete_virtual_district,
    generate_district_metering_area,
    generate_service_area,
    generate_sub_district_metering_area,
    generate_virtual_district,
    get_all_district_metering_area_ids,
    get_all_district_metering_areas,
    get_all_service_areas,
    get_all_virtual_districts,
    get_district_metering_area,
    get_district_metering_area_schema,
    get_region,
    get_region_schema,
    get_service_area,
    get_service_area_schema,
    get_virtual_district,
    get_virtual_district_schema,
    set_district_metering_area,
    set_region,
    set_service_area,
    set_virtual_district,
)

router = APIRouter()

############################################################
# region 32
############################################################

@router.get("/calculateregion/")
async def fastapi_calculate_region(network: str, time_index: int) -> dict[str, Any]:
    return calculate_region(network, time_index)

@router.get("/getregionschema/")
async def fastapi_get_region_schema(network: str) -> dict[str, dict[str, Any]]:
    return get_region_schema(network)

@router.get("/getregion/")
async def fastapi_get_region(network: str, id: str) -> dict[str, Any]:
    return get_region(network, id)

@router.post("/setregion/", response_model=None)
async def fastapi_set_region(network: str, req: Request) -> ChangeSet:
    props = await req.json()
    return set_region(network, ChangeSet(props))

@router.post("/addregion/", response_model=None)
async def fastapi_add_region(network: str, req: Request) -> ChangeSet:
    props = await req.json()
    return add_region(network, ChangeSet(props))

@router.post("/deleteregion/", response_model=None)
async def fastapi_delete_region(network: str, req: Request) -> ChangeSet:
    props = await req.json()
    return delete_region(network, ChangeSet(props))

@router.get("/getallregions/")
async def fastapi_get_all_regions(network: str) -> list[dict[str, Any]]:
    return get_all_regions(network)

@router.post("/generateregion/", response_model=None)
async def fastapi_generate_region(
    network: str, inflate_delta: float
) -> ChangeSet:
    return generate_region(network, inflate_delta)


############################################################
# district_metering_area 33
############################################################

@router.get("/calculatedistrictmeteringarea/")
async def fastapi_calculate_district_metering_area(
    network: str, req: Request
) -> list[list[str]]:
    props = await req.json()
    nodes = props["nodes"]
    part_count = props["part_count"]
    part_type = props["part_type"]
    return calculate_district_metering_area(
        network, nodes, part_count, part_type
    )

@router.get("/calculatedistrictmeteringareaforregion/")
async def fastapi_calculate_district_metering_area_for_region(
    network: str, req: Request
) -> list[list[str]]:
    props = await req.json()
    region = props["region"]
    part_count = props["part_count"]
    part_type = props["part_type"]
    return calculate_district_metering_area_for_region(
        network, region, part_count, part_type
    )

@router.get("/calculatedistrictmeteringareafornetwork/")
async def fastapi_calculate_district_metering_area_for_network(
    network: str, req: Request
) -> list[list[str]]:
    props = await req.json()
    part_count = props["part_count"]
    part_type = props["part_type"]
    return calculate_district_metering_area_for_network(network, part_count, part_type)

@router.get("/getdistrictmeteringareaschema/")
async def fastapi_get_district_metering_area_schema(
    network: str,
) -> dict[str, dict[str, Any]]:
    return get_district_metering_area_schema(network)

@router.get("/getdistrictmeteringarea/")
async def fastapi_get_district_metering_area(network: str, id: str) -> dict[str, Any]:
    return get_district_metering_area(network, id)

@router.post("/setdistrictmeteringarea/", response_model=None)
async def fastapi_set_district_metering_area(network: str, req: Request) -> ChangeSet:
    props = await req.json()
    return set_district_metering_area(network, ChangeSet(props))

@router.post("/adddistrictmeteringarea/", response_model=None)
async def fastapi_add_district_metering_area(network: str, req: Request) -> ChangeSet:
    props = await req.json()
    # boundary should be [(x,y), (x,y)]
    boundary = props.get("boundary", [])
    newBoundary = []
    for pt in boundary:
        if len(pt) >= 2:
            newBoundary.append((pt[0], pt[1]))
    props["boundary"] = newBoundary
    return add_district_metering_area(network, ChangeSet(props))

@router.post("/deletedistrictmeteringarea/", response_model=None)
async def fastapi_delete_district_metering_area(
    network: str, req: Request
) -> ChangeSet:
    props = await req.json()
    return delete_district_metering_area(network, ChangeSet(props))

@router.get("/getalldistrictmeteringareaids/")
async def fastapi_get_all_district_metering_area_ids(network: str) -> list[str]:
    return get_all_district_metering_area_ids(network)

@router.get("/getalldistrictmeteringareas/")
async def getalldistrictmeteringareas(network: str) -> list[dict[str, Any]]:
    return get_all_district_metering_areas(network)

@router.post("/generatedistrictmeteringarea/", response_model=None)
async def fastapi_generate_district_metering_area(
    network: str, part_count: int, part_type: int, inflate_delta: float
) -> ChangeSet:
    return generate_district_metering_area(
        network, part_count, part_type, inflate_delta
    )

@router.post("/generatesubdistrictmeteringarea/", response_model=None)
async def fastapi_generate_sub_district_metering_area(
    network: str, dma: str, part_count: int, part_type: int, inflate_delta: float
) -> ChangeSet:
    return generate_sub_district_metering_area(
        network, dma, part_count, part_type, inflate_delta
    )


############################################################
# service_area 34
############################################################

@router.get("/calculateservicearea/")
async def fastapi_calculate_service_area(
    network: str, time_index: int
) -> dict[str, Any]:
    return calculate_service_area(network, time_index)

@router.get("/getserviceareaschema/")
async def fastapi_get_service_area_schema(network: str) -> dict[str, dict[str, Any]]:
    return get_service_area_schema(network)

@router.get("/getservicearea/")
async def fastapi_get_service_area(network: str, id: str) -> dict[str, Any]:
    return get_service_area(network, id)

@router.post("/setservicearea/", response_model=None)
async def fastapi_set_service_area(network: str, req: Request) -> ChangeSet:
    props = await req.json()
    return set_service_area(network, ChangeSet(props))

@router.post("/addservicearea/", response_model=None)
async def fastapi_add_service_area(network: str, req: Request) -> ChangeSet:
    props = await req.json()
    return add_service_area(network, ChangeSet(props))

@router.post("/deleteservicearea/", response_model=None)
async def fastapi_delete_service_area(network: str, req: Request) -> ChangeSet:
    props = await req.json()
    return delete_service_area(network, ChangeSet(props))

@router.get("/getallserviceareas/")
async def fastapi_get_all_service_areas(network: str) -> list[dict[str, Any]]:
    return get_all_service_areas(network)

@router.post("/generateservicearea/", response_model=None)
async def fastapi_generate_service_area(
    network: str, inflate_delta: float
) -> ChangeSet:
    return generate_service_area(network, inflate_delta)


############################################################
# virtual_district 35
############################################################

@router.get("/calculatevirtualdistrict/")
async def fastapi_calculate_virtual_district(
    network: str, centers: list[str]
) -> dict[str, list[Any]]:
    return calculate_virtual_district(network, centers)

@router.get("/getvirtualdistrictschema/")
async def fastapi_get_virtual_district_schema(
    network: str,
) -> dict[str, dict[str, Any]]:
    return get_virtual_district_schema(network)

@router.get("/getvirtualdistrict/")
async def fastapi_get_virtual_district(network: str, id: str) -> dict[str, Any]:
    return get_virtual_district(network, id)

@router.post("/setvirtualdistrict/", response_model=None)
async def fastapi_set_virtual_district(network: str, req: Request) -> ChangeSet:
    props = await req.json()
    return set_virtual_district(network, ChangeSet(props))

@router.post("/addvirtualdistrict/", response_model=None)
async def fastapi_add_virtual_district(network: str, req: Request) -> ChangeSet:
    props = await req.json()
    return add_virtual_district(network, ChangeSet(props))

@router.post("/deletevirtualdistrict/", response_model=None)
async def fastapi_delete_virtual_district(network: str, req: Request) -> ChangeSet:
    props = await req.json()
    return delete_virtual_district(network, ChangeSet(props))

@router.get("/getallvirtualdistrict/")
async def fastapi_get_all_virtual_district(network: str) -> list[dict[str, Any]]:
    return get_all_virtual_districts(network)

@router.post("/generatevirtualdistrict/", response_model=None)
async def fastapi_generate_virtual_district(
    network: str, inflate_delta: float, req: Request
) -> ChangeSet:
    props = await req.json()
    return generate_virtual_district(network, props["centers"], inflate_delta)

@router.get("/calculatedistrictmeteringareafornodes/")
async def fastapi_calculate_district_metering_area_for_nodes(
    network: str, req: Request
) -> list[list[str]]:
    props = await req.json()
    nodes = props["nodes"]
    part_count = props["part_count"]
    part_type = props["part_type"]
    return calculate_district_metering_area_for_nodes(
        network, nodes, part_count, part_type
    )
