from aiohttp import web

from maps_adv.billing_proxy.lib.domain import (
    ClientsDomain,
    OrdersDomain,
    ProductsDomain,
)
from tvmauth import TvmClient

from . import middlewares
from .api_providers import (
    BalanceApiProvider,
    ClientsApiProvider,
    OrdersApiProvider,
    ProductsApiProvider,
)
from .resources import balance, clients, orders, products, system


def create(
    clients_domain: ClientsDomain,
    orders_domain: OrdersDomain,
    products_domain: ProductsDomain,
    tvm_client: TvmClient,
):
    system_resources = system.Resources()
    balance_resources = balance.Resources(BalanceApiProvider(orders_domain))
    clients_resources = clients.Resources(
        ClientsApiProvider(clients_domain), tvm_client
    )
    orders_resources = orders.Resources(OrdersApiProvider(orders_domain))
    products_resources = products.Resources(ProductsApiProvider(products_domain))

    api = web.Application(
        middlewares=[
            middlewares.handle_domain_exception,
            middlewares.handle_balance_api_exception,
            middlewares.handle_validation_exception,
            middlewares.handle_wrong_balance_service_id,
            middlewares.handle_invalid_reconciliation_params,
        ]
    )
    api.add_routes(
        [
            web.post(r"/clients/", clients_resources.create_client),
            web.post(r"/clients/register/", clients_resources.register_client),
            web.get(r"/clients/", clients_resources.list_clients),
            web.post(
                r"/clients/by-account-manager/",
                clients_resources.retrieve_clients_by_account_manager,
            ),
            web.get(r"/clients/{client_id:\d+}/", clients_resources.retrieve_client),
            web.post(
                r"/clients/set-account-manager/",
                clients_resources.set_account_manager_for_client,
            ),
            web.post(
                r"/clients/find-client-by-uid/", clients_resources.find_client_by_uid
            ),
            web.get(
                r"/clients/{client_id:\d+}/contracts/",
                clients_resources.list_client_contracts,
            ),
            web.get(
                r"/clients/{client_id:\d+|internal}/orders/",
                orders_resources.list_client_orders,
            ),
            web.post(
                r"/clients/{client_id:\d+}/accept_offer/",
                clients_resources.set_client_has_accepted_offer,
            ),
            web.get(
                r"/clients/{client_id:\d+}/representatives/",
                clients_resources.list_client_representatives,
            ),
            web.post(
                r"/clients/{client_id:\d+}/add-user/{uid:\d+}/",
                clients_resources.add_user_to_client,
            ),
            web.get(r"/agencies/", clients_resources.list_agencies),
            web.get(
                r"/agencies/{agency_id:\d+}/contracts/",
                clients_resources.list_agency_contracts,
            ),
            web.get(
                r"/agencies/{agency_id:\d+|internal}/clients/",
                clients_resources.list_agency_clients,
            ),
            web.patch(
                r"/agencies/{agency_id:\d+|internal}/clients/",
                clients_resources.add_clients_to_agency,
            ),
            web.delete(
                r"/agencies/{agency_id:\d+|internal}/clients/",
                clients_resources.remove_clients_from_agency,
            ),
            web.get(
                r"/agencies/{agency_id:\d+|internal}/orders/",
                orders_resources.list_agency_orders,
            ),
            web.post(
                r"/agencies/{agency_id:\d+}/accept_offer/",
                clients_resources.set_agency_has_accepted_offer,
            ),
            web.get(
                r"/agencies/{agency_id:\d+}/representatives/",
                clients_resources.list_agency_representatives,
            ),
            web.post(
                r"/agencies/{agency_id:\d+}/add-user/{uid:\d+}/",
                clients_resources.add_user_to_agency,
            ),
            web.post(r"/orders/", orders_resources.create_order),
            web.get(r"/orders/{order_id:\d+}/", orders_resources.retrieve_order),
            web.get(
                r"/orders/by-external-id/{external_id:\d+}/",
                orders_resources.retrieve_order_by_external_id,
            ),
            web.post(r"/orders/by-order-ids/", orders_resources.retrieve_orders),
            web.post(
                r"/orders/by-account-manager/",
                orders_resources.retrieve_order_ids_for_account,
            ),
            web.post(
                r"/orders/{order_id:\d+}/deposit/",
                orders_resources.create_deposit_request,
            ),
            web.post(r"/orders/stats/", orders_resources.list_orders_stats),
            web.post(r"/orders/discounts/", orders_resources.list_orders_discounts),
            web.post(r"/orders/active/", orders_resources.list_active_orders),
            web.post(r"/orders/charge/", orders_resources.charge_orders),
            web.put(r"/orders/{order_id:\d+}/", orders_resources.update_order),
            web.post(r"/orders/debits/", orders_resources.list_orders_debits),
            web.get(r"/products/", products_resources.list_products),
            web.post(r"/products/", products_resources.create_product),
            web.post(
                r"/products/by-service-ids/",
                products_resources.list_products_by_service_ids,
            ),
            web.get(
                r"/products/{product_id:\d+}/", products_resources.retrieve_product
            ),
            web.put(r"/products/{product_id:\d+}/", products_resources.update_product),
            web.post(r"/products/advise/", products_resources.advise_product),
            web.post(
                r"/products/{product_id:\d+}/cpm/", products_resources.calculate_cpm
            ),
            web.get(
                r"/products/{product_id:\d+}/clients/",
                products_resources.list_clients_bound_to_product,
            ),
            web.patch(
                r"/products/{product_id:\d+}/clients/",
                products_resources.bind_client_to_product,
            ),
            web.delete(
                r"/products/{product_id:\d+}/clients/",
                products_resources.unbind_client_from_product,
            ),
            web.post(
                r"/notify/BalanceClient/NotifyOrder2/", balance_resources.notify_orders
            ),
            web.post(
                r"/geoprod/notify/BalanceClient/NotifyOrder2/",
                balance_resources.notify_orders_from_geoprod,
            ),
            web.get(r"/reconciliation/", balance_resources.reconciliation),
            # service handle for debug and force recalculation
            web.post(
                r"/geoprod/reconciliation/", balance_resources.geoprod_reconciliation
            ),
            web.get(r"/ping", system_resources.ping),
        ]
    )

    return api
