from datetime import datetime

from motor import motor_asyncio
from pymongo import ASCENDING, DESCENDING

from app.config import config
from app.utils.logger_util import logger

asc = ASCENDING
desc = DESCENDING

client = motor_asyncio.AsyncIOMotorClient(config["MONGO_URL"])
db = client.get_database(config["MONGO_DB"])

users_collection = db.get_collection("users")

roles_collection = db.get_collection("roles")

clients_collection = db.get_collection("clients")
client_pallets_collection = db.get_collection("client_pallets")
client_boxes_collection = db.get_collection("client_boxes")

products_collection = db.get_collection("products")

services_collection = db.get_collection("services")
service_kits_collection = db.get_collection("service_kits")
service_types_collection = db.get_collection("service_types")
service_categories_collection = db.get_collection("service_categories")

templates_collection = db.get_collection("templates")
template_sizes_collection = db.get_collection("template_sizes")
template_attributes_collection = db.get_collection("template_attributes")

shipping_warehouses_collection = db.get_collection("shipping_warehouses")

marketplaces_collection = db.get_collection("marketplaces")
base_marketplaces_collection = db.get_collection("base_marketplaces")

deals_collection = db.get_collection("deals")
deals_status_history_collection = db.get_collection("deals_status_history")

departments_collection = db.get_collection("departments")
department_sections_collection = db.get_collection("department_sections")

positions_collection = db.get_collection("positions")

pay_rates_collection = db.get_collection("pay_rates")
pay_rate_schemes_collection = db.get_collection("pay_rate_schemes")

projects_collection = db.get_collection("projects")

boards_collection = db.get_collection("boards")

statuses_collection = db.get_collection("statuses")

payment_records_collection = db.get_collection("payment_records")

tasks_collection = db.get_collection("tasks")

work_shifts_collection = db.get_collection("work_shifts")
time_tracking_collection = db.get_collection("time_tracking")

transactions_collection = db.get_collection("transactions")
transaction_tags_collection = db.get_collection("transaction_tags")


async def migrate():
    try:
        await users_collection.create_index("id", unique=True)

        await roles_collection.create_index("id", unique=True)
        await roles_collection.create_index("key")
        await roles_collection.create_index("name")

        await clients_collection.create_index("id", unique=True)
        await clients_collection.create_index("name")
        await clients_collection.create_index("companyName")

        await client_pallets_collection.create_index("id", unique=True)
        await client_pallets_collection.create_index("createdAt")
        await client_pallets_collection.create_index("clientId")

        await client_boxes_collection.create_index("id", unique=True)
        await client_boxes_collection.create_index("createdAt")
        await client_boxes_collection.create_index("clientId")
        await client_boxes_collection.create_index("palletId")

        await products_collection.create_index("id", unique=True)
        await products_collection.create_index("client_id")
        await products_collection.create_index("name")
        await products_collection.create_index("article")
        await products_collection.create_index("factoryArticle")
        await products_collection.create_index("barcodes")

        await services_collection.create_index("id", unique=True)
        await services_collection.create_index("name")
        await services_collection.create_index("price")
        await services_collection.create_index("serviceType")

        await service_types_collection.create_index("id", unique=True)
        await service_types_collection.create_index("name")

        await service_categories_collection.create_index("id", unique=True)
        await service_categories_collection.create_index("name")

        await service_kits_collection.create_index("id", unique=True)
        await service_kits_collection.create_index("name")

        await templates_collection.create_index("id", unique=True)
        await templates_collection.create_index("name")

        await template_sizes_collection.create_index("id", unique=True)
        await template_sizes_collection.create_index("key")
        await template_sizes_collection.create_index("name")
        await template_sizes_collection.create_index("height")
        await template_sizes_collection.create_index("width")

        await template_attributes_collection.create_index("id", unique=True)
        await template_attributes_collection.create_index("key")
        await template_attributes_collection.create_index("name")

        await shipping_warehouses_collection.create_index("id", unique=True)
        await shipping_warehouses_collection.create_index("name")

        await marketplaces_collection.create_index("id", unique=True)
        await marketplaces_collection.create_index("name")
        await marketplaces_collection.create_index("clientId")
        await marketplaces_collection.create_index("client.id")

        await base_marketplaces_collection.create_index("id", unique=True)
        await base_marketplaces_collection.create_index("key")
        await base_marketplaces_collection.create_index("name")

        await deals_collection.create_index("id", unique=True)
        await deals_collection.create_index("name")
        await deals_collection.create_index("createdAt")

        await department_sections_collection.create_index("id", unique=True)
        await department_sections_collection.create_index("departmentId")
        await department_sections_collection.create_index("name")
        await department_sections_collection.create_index("parentDepartmentSectionId")

        await positions_collection.create_index("id", unique=True)
        await positions_collection.create_index("key")
        await positions_collection.create_index("name")

        await pay_rates_collection.create_index("id", unique=True)
        await pay_rates_collection.create_index("name")

        await projects_collection.create_index("id", unique=True)
        await projects_collection.create_index("name")

        await boards_collection.create_index("id", unique=True)
        await boards_collection.create_index("name")
        await boards_collection.create_index("projectId")

        await statuses_collection.create_index("id", unique=True)
        await statuses_collection.create_index("name")
        await statuses_collection.create_index("boardId")

        await payment_records_collection.create_index("id", unique=True)
        await payment_records_collection.create_index("createdAt")

        await tasks_collection.create_index("taskId", unique=True)
        await tasks_collection.create_index("status")
        await tasks_collection.create_index("marketplaceId")
        await tasks_collection.create_index("createdAt")

        await work_shifts_collection.create_index("id", unique=True)
    except Exception as e:
        logger.debug(e)


async def get_next_id(collection) -> int:
    last_id = 1
    try:
        last = await collection.find({}).sort("id", desc).limit(1).to_list()
        last_id = last[0]["id"] + 1
    finally:
        return last_id


def created_at(date: datetime = None, format: str = "%Y-%m-%dT%H:%M:%S"):
    if not date:
        date = datetime.now()

    return date.strftime(format)


async def get_deals_total_prices(*deals: dict) -> dict:
    results = {}
    for deal in deals:
        total_price = 0

        for service in deal.get("services", []):
            total_price += service.get("price", 0) * service.get("quantity", 1)

        for product in deal.get("products", []):
            for service in product.get("services", []):
                total_price += service.get("price", 0) * service.get("quantity", 1) * product.get("quantity", 1)

        results[deal["id"]] = total_price

    return results


async def additional_deals_data(*deals: dict, full: bool):
    client_names = {deal["clientName"] for deal in deals}
    service_ids = set()
    product_ids = set()
    user_ids = set()

    for deal in deals:
        for service in deal.get("services", []):
            service_ids.add(service["serviceId"])
        for product in deal.get("products", []):
            product_ids.add(product["productId"])
            for service in product.get("services", []):
                service_ids.add(service["serviceId"])
        for employee in deal.get("employees", []):
            user_ids.add(employee["userId"])

        for history in deal.get("statusHistory", []):
            if "userId" in history:
                user_ids.add(history["userId"])

    projects = {
        project["id"]: project async for project in projects_collection.find({}, {"_id": False})
    }

    boards = {
        board["id"]: board async for board in boards_collection.find({}, {"_id": False})
    }

    statuses = {
        status["id"]: status async for status in statuses_collection.find({}, {"_id": False})
    }

    clients = {
        client["name"]: client async for client in clients_collection.find(
            {"name": {"$in": list(client_names)}}, {"_id": False}
        )
    }

    products = {}
    if full:
        products = {
            product["id"]: product async for product in products_collection.find(
                {"id": {"$in": list(product_ids)}}, {"_id": False}
            )
        }

    services = {}
    if full:
        services = {
            service["id"]: service async for service in services_collection.find(
                {"id": {"$in": list(service_ids)}}, {"_id": False}
            )
        }

    users = {}
    if full:
        users = {
            user["id"]: user async for user in users_collection.find(
                {"id": {"$in": list(user_ids)}}, {"_id": False}
            )
        }

    for deal in deals:
        deal["shipmentWarehouseName"] = deal["shippingWarehouse"]
        deal["shippingWarehouse"] = {"name": deal["shippingWarehouse"]}

        deal["status"] = statuses.get(deal["statusId"])
        deal["board"] = boards.get(deal["boardId"])
        deal["project"] = projects.get(deal["board"]["projectId"])

        deal["board"]["project"] = projects.get(deal["board"]["projectId"])
        deal["board"]["dealStatuses"] = [status for status in statuses.values() if status["boardId"] == deal["boardId"]]

        deal["client"] = clients.get(deal["clientName"], {})
        if deal["client"]:
            deal["clientId"] = deal["client"]["id"]

        total_price = 0
        total_products = 0

        enriched_services = []
        for service in deal.get("services", []):
            if full:
                service["service"] = services.get(service["serviceId"])
            enriched_services.append(service)
            total_price += service.get("price", 0) * service.get("quantity", 1)
        deal["services"] = enriched_services

        enriched_products = []
        selected = set()
        for product in deal.get("products", []):
            product_id = product["productId"]
            if product_id in selected:
                continue
            if full:
                product["product"] = products.get(product["productId"])

            enriched_services = []
            for service in product.get("services", []):
                if full:
                    service["service"] = services.get(service["serviceId"])
                enriched_services.append(service)
                total_price += service.get("price", 0) * service.get("quantity", 1) * product.get("quantity", 1)

            product["services"] = enriched_services
            selected.add(product_id)

            enriched_products.append(product)

            total_products += product.get("quantity", 1)

        deal["products"] = enriched_products

        enriched_employees = []
        for employee in deal.get("employees", []):
            if full:
                employee["user"] = users.get(employee["userId"])
            enriched_employees.append(employee)
        deal["employees"] = enriched_employees

        enriched_history = []
        for history in deal.get("statusHistory", []):
            if full:
                history["user"] = users.get(history.get("userId"))
                history["fromStatus"] = statuses.get(history.get("fromStatusId"))
                history["toStatus"] = statuses.get(history.get("toStatusId"))
            enriched_history.append(history)
        deal["statusHistory"] = enriched_history

        deal["totalPrice"] = total_price
        deal["totalProducts"] = total_products

    return deals


async def get_all_summaries(full: bool):
    if not full:
        deals = await deals_collection.find({
            "$and": [
                {
                    "$or": [
                        {"isDeleted": False},
                        {"isDeleted": {"$exists": False}}
                    ]
                },
                {
                    "$or": [
                        {"isCompleted": False},
                        {"isCompleted": {"$exists": False}}
                    ]
                }
            ]
        }, {"_id": False}).sort("id", asc).to_list()
    else:
        deals = await deals_collection.find({
            "$and": [
                {
                    "$or": [
                        {"isDeleted": False},
                        {"isDeleted": {"$exists": False}}
                    ]
                }
            ]
        }, {"_id": False}).sort("id", asc).to_list()
    return await additional_deals_data(*deals, full=full)
