from datetime import datetime, timezone
import re
import unicodedata
from bson import ObjectId
from pymongo import MongoClient
from MongoDBConnection import MONGO_URI, DB_NAME

client = MongoClient(MONGO_URI)
db = client[DB_NAME]

collection = db["action_logs"]
orders_collection = db["orders"]
tickets_collection = db["tickets"]
transactions_collection = db["transactions"]
users_collection = db["users"]
products_collection = db["products"]
categories_collection = db["categories"]
banners_collection = db["banners"]

ALLOWED_ACTOR_ROLES = ["admin", "staff"]


class ActionLogModel:
    @classmethod
    def write_log(cls, data: dict):
        actor_role = str(data.get("actorRole") or "").strip().lower()
        actor_id = str(data.get("actorId") or "").strip()

        if actor_role not in ALLOWED_ACTOR_ROLES:
            return False

        if not actor_id:
            return False

        document = {
            "createdAt": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.000Z"),
            **data,
        }
        collection.insert_one(document)
        return True

    @classmethod
    def _safe_body(cls, row: dict):
        body = row.get("body")
        return body if isinstance(body, dict) else {}

    @classmethod
    def _build_action_payload(
        cls,
        action_key: str,
        action_summary: str,
        *,
        action_count: int | None = None,
        action_rows: int | None = None,
        action_status: str | None = None,
        action_params: dict | None = None,
    ):
        payload = {
            "actionKey": action_key,
            "actionSummary": action_summary,
        }

        if action_count is not None:
            payload["actionCount"] = action_count

        if action_rows is not None:
            payload["actionRows"] = action_rows

        if action_status is not None:
            payload["actionStatus"] = action_status

        if action_params:
            payload["actionParams"] = action_params

        return payload

    @classmethod
    def _normalize_search_text(cls, value: str):
        text = str(value or "").strip().lower()
        text = unicodedata.normalize("NFD", text)
        text = "".join(ch for ch in text if unicodedata.category(ch) != "Mn")
        text = text.replace("đ", "d")
        return text

    @classmethod
    def _parse_object_id(cls, raw_value):
        try:
            value = str(raw_value or "").strip()
            if not value:
                return None
            return ObjectId(value)
        except Exception:
            return None

    @classmethod
    def _parse_object_ids(cls, raw_values):
        ids = []
        if not isinstance(raw_values, list):
            return ids

        seen = set()
        for raw in raw_values:
            obj_id = cls._parse_object_id(raw)
            if not obj_id:
                continue
            key = str(obj_id)
            if key in seen:
                continue
            seen.add(key)
            ids.append(obj_id)
        return ids

    @classmethod
    def _money(cls, value):
        try:
            return f"${float(value or 0):,.2f}"
        except Exception:
            return "$0.00"

    @classmethod
    def _short_join(cls, values, limit=5):
        cleaned = []
        seen = set()

        for raw in values or []:
            value = str(raw or "").strip()
            if not value or value in seen:
                continue
            seen.add(value)
            cleaned.append(value)

        if not cleaned:
            return "N/A"

        if len(cleaned) <= limit:
            return ", ".join(cleaned)

        return f"{', '.join(cleaned[:limit])} +{len(cleaned) - limit} more"

    @classmethod
    def _format_permissions(cls, permissions):
        if not isinstance(permissions, list) or not permissions:
            return "none"
        return ", ".join([str(p).strip() for p in permissions if str(p).strip()]) or "none"

    @classmethod
    def _extract_path_id(cls, path: str, pattern: str):
        match = re.search(pattern, path)
        return match.group(1) if match else ""

    @classmethod
    def _get_user_email_by_customer_id(cls, user_id: str):
        user_id = str(user_id or "").strip()
        if not user_id:
            return ""

        obj_id = cls._parse_object_id(user_id)
        query_candidates = []
        if obj_id:
            query_candidates.append({"_id": obj_id})
        query_candidates.append({"id": user_id})

        for query in query_candidates:
            user = users_collection.find_one(query, {"email": 1})
            if user and user.get("email"):
                return str(user.get("email")).strip()

        return ""

    @classmethod
    def _find_staff_by_identifier(cls, staff_id: str):
        staff_id = str(staff_id or "").strip()
        if not staff_id:
            return None

        obj_id = cls._parse_object_id(staff_id)
        query_candidates = []
        if obj_id:
            query_candidates.append({"_id": obj_id})
        query_candidates.append({"id": staff_id})

        for query in query_candidates:
            user = users_collection.find_one(query)
            if user:
                return user

        return None

    @classmethod
    def _find_topup_by_id(cls, ticket_id: str):
        ticket_id = str(ticket_id or "").strip()
        if not ticket_id:
            return None
        return transactions_collection.find_one({"id": ticket_id})

    @classmethod
    def _find_ticket_by_id(cls, ticket_id: str):
        ticket_id = str(ticket_id or "").strip()
        if not ticket_id:
            return None
        return tickets_collection.find_one({"id": ticket_id})

    @classmethod
    def _find_product_by_identifier(cls, identifier: str):
        identifier = str(identifier or "").strip()
        if not identifier:
            return None

        obj_id = cls._parse_object_id(identifier)
        query_candidates = []
        if obj_id:
            query_candidates.append({"_id": obj_id})
        query_candidates.append({"productId": identifier})
        query_candidates.append({"id": identifier})

        for query in query_candidates:
            product = products_collection.find_one(query)
            if product:
                return product

        return None

    @classmethod
    def _find_category_by_identifier(cls, identifier: str):
        identifier = str(identifier or "").strip()
        if not identifier:
            return None

        obj_id = cls._parse_object_id(identifier)
        query_candidates = []
        if obj_id:
            query_candidates.append({"_id": obj_id})
        query_candidates.append({"_id": identifier})
        query_candidates.append({"slug": identifier})

        for query in query_candidates:
            category = categories_collection.find_one(query)
            if category:
                return category

        return None

    @classmethod
    def _find_banner_by_identifier(cls, banner_id: str):
        banner_id = str(banner_id or "").strip()
        if not banner_id:
            return None
        return banners_collection.find_one({"id": banner_id})

    @classmethod
    def _find_order_by_identifier(cls, identifier: str):
        identifier = str(identifier or "").strip()
        if not identifier:
            return None

        conditions = [
            {"orderId": identifier},
            {"id": identifier},
        ]

        obj_id = cls._parse_object_id(identifier)
        if obj_id:
            conditions.insert(0, {"_id": obj_id})

        return orders_collection.find_one({"$or": conditions})

    @classmethod
    def _find_orders_by_doc_ids(cls, raw_doc_ids):
        object_ids = cls._parse_object_ids(raw_doc_ids)
        if not object_ids:
            return []

        return list(
            orders_collection.find(
                {"_id": {"$in": object_ids}},
                {
                    "orderId": 1,
                    "id": 1,
                    "status": 1,
                    "tracking": 1,
                    "trackingNumber": 1,
                    "trackingLink": 1,
                    "refundAmount": 1,
                    "refundTxId": 1,
                },
            )
        )

    @classmethod
    def _order_label(cls, doc: dict):
        if not doc:
            return ""
        return str(doc.get("orderId") or doc.get("id") or doc.get("_id") or "").strip()

    @classmethod
    def _build_order_batch_summary(cls, body: dict):
        docs = cls._find_orders_by_doc_ids(body.get("docIds"))
        order_ids = [cls._order_label(doc) for doc in docs]
        ids_text = cls._short_join(order_ids)
        count = len(order_ids)
        new_status = str(body.get("status") or "").strip()
        tracking_number = str(body.get("trackingNumber") or "").strip()
        tracking_link = str(body.get("trackingLink") or "").strip()

        if new_status == "Printing":
            return cls._build_action_payload(
                "logMoveToPrintingDetailed",
                f"Move {count} order(s) to Printing | IDs: {ids_text}",
                action_count=count,
                action_status=new_status,
                action_params={
                    "count": count,
                    "ids": ids_text,
                },
            )

        if new_status == "Shipped":
            if tracking_number and tracking_link:
                return cls._build_action_payload(
                    "logConfirmShippedDetailedWithTrackingAndLink",
                    f"Confirm shipment for {count} order(s) | IDs: {ids_text} | tracking: {tracking_number} | link: {tracking_link}",
                    action_count=count,
                    action_status=new_status,
                    action_params={
                        "count": count,
                        "ids": ids_text,
                        "tracking": tracking_number,
                        "link": tracking_link,
                    },
                )

            if tracking_number:
                return cls._build_action_payload(
                    "logConfirmShippedDetailedWithTracking",
                    f"Confirm shipment for {count} order(s) | IDs: {ids_text} | tracking: {tracking_number}",
                    action_count=count,
                    action_status=new_status,
                    action_params={
                        "count": count,
                        "ids": ids_text,
                        "tracking": tracking_number,
                    },
                )

            return cls._build_action_payload(
                "logConfirmShippedDetailed",
                f"Confirm shipment for {count} order(s) | IDs: {ids_text}",
                action_count=count,
                action_status=new_status,
                action_params={
                    "count": count,
                    "ids": ids_text,
                },
            )

        return cls._build_action_payload(
            "logUpdateOrderStatusDetailed",
            f"Update {count} order(s) to {new_status or 'Unknown'} | IDs: {ids_text}",
            action_count=count,
            action_status=new_status or None,
            action_params={
                "count": count,
                "status": new_status or "Unknown",
                "ids": ids_text,
            },
        )

    @classmethod
    def _build_order_single_status_summary(cls, path: str, body: dict):
        identifier = cls._extract_path_id(path, r"/api/orders/admin/([^/]+)/status$")
        order = cls._find_order_by_identifier(identifier)
        order_id = cls._order_label(order) or identifier or "N/A"
        new_status = str(body.get("status") or "").strip()
        tracking_number = str(body.get("trackingNumber") or "").strip()
        tracking_link = str(body.get("trackingLink") or "").strip()

        if new_status == "Printing":
            return cls._build_action_payload(
                "logMoveToPrintingDetailed",
                f"Move 1 order(s) to Printing | IDs: {order_id}",
                action_count=1,
                action_status=new_status,
                action_params={
                    "count": 1,
                    "ids": order_id,
                },
            )

        if new_status == "Shipped":
            if tracking_number and tracking_link:
                return cls._build_action_payload(
                    "logConfirmShippedDetailedWithTrackingAndLink",
                    f"Confirm shipment for 1 order(s) | IDs: {order_id} | tracking: {tracking_number} | link: {tracking_link}",
                    action_count=1,
                    action_status=new_status,
                    action_params={
                        "count": 1,
                        "ids": order_id,
                        "tracking": tracking_number,
                        "link": tracking_link,
                    },
                )

            if tracking_number:
                return cls._build_action_payload(
                    "logConfirmShippedDetailedWithTracking",
                    f"Confirm shipment for 1 order(s) | IDs: {order_id} | tracking: {tracking_number}",
                    action_count=1,
                    action_status=new_status,
                    action_params={
                        "count": 1,
                        "ids": order_id,
                        "tracking": tracking_number,
                    },
                )

            return cls._build_action_payload(
                "logConfirmShippedDetailed",
                f"Confirm shipment for 1 order(s) | IDs: {order_id}",
                action_count=1,
                action_status=new_status,
                action_params={
                    "count": 1,
                    "ids": order_id,
                },
            )

        return cls._build_action_payload(
            "logUpdateOrderStatusDetailed",
            f"Update 1 order(s) to {new_status or 'Unknown'} | IDs: {order_id}",
            action_count=1,
            action_status=new_status or None,
            action_params={
                "count": 1,
                "status": new_status or "Unknown",
                "ids": order_id,
            },
        )

    @classmethod
    def _build_order_cancel_summary(cls, path: str):
        identifier = cls._extract_path_id(path, r"/api/orders/admin/([^/]+)/cancel$")
        order = cls._find_order_by_identifier(identifier)

        order_id = cls._order_label(order) or identifier or "N/A"
        refund_amount = cls._money(order.get("refundAmount", 0) if order else 0)
        refund_tx_id = str(order.get("refundTxId") or "").strip() if order else ""

        if refund_tx_id:
            return cls._build_action_payload(
                "logCancelOrderDetailedWithTx",
                f"Cancel order {order_id} | refund: {refund_amount} | refundTx: {refund_tx_id}",
                action_count=1,
                action_status="Cancelled",
                action_params={
                    "id": order_id,
                    "refund": refund_amount,
                    "refundTx": refund_tx_id,
                },
            )

        return cls._build_action_payload(
            "logCancelOrderDetailed",
            f"Cancel order {order_id} | refund: {refund_amount}",
            action_count=1,
            action_status="Cancelled",
            action_params={
                "id": order_id,
                "refund": refund_amount,
            },
        )

    @classmethod
    def _build_topup_summary(cls, body: dict):
        ticket_id = str(body.get("ticketId") or "").strip()
        status = str(body.get("status") or "").strip().lower()
        reject_reason = str(body.get("rejectReason") or "").strip()

        tx = cls._find_topup_by_id(ticket_id)
        email = cls._get_user_email_by_customer_id(tx.get("id_khach_hang")) if tx else ""
        amount = cls._money(tx.get("numericAmount", 0) if tx else 0)

        if status == "approved":
            return cls._build_action_payload(
                "logApproveTopupDetailed",
                f"Approve topup {ticket_id} | amount: +{amount} | email: {email or 'N/A'}",
                action_status="Approved",
                action_params={
                    "id": ticket_id,
                    "amount": f"+{amount}",
                    "email": email or "N/A",
                },
            )

        if status == "rejected":
            reason_text = reject_reason or (str(tx.get("rejectReason") or "").strip() if tx else "")
            return cls._build_action_payload(
                "logRejectTopupDetailed",
                f"Reject topup {ticket_id} | email: {email or 'N/A'} | reason: {reason_text or 'N/A'}",
                action_status="Rejected",
                action_params={
                    "id": ticket_id,
                    "email": email or "N/A",
                    "reason": reason_text or "N/A",
                },
            )

        final_status = str(tx.get("status") or status or "").strip() if tx else status
        return cls._build_action_payload(
            "logUpdateTopupDetailed",
            f"Update topup {ticket_id} | status: {final_status or 'N/A'} | amount: {amount} | email: {email or 'N/A'}",
            action_status=final_status or None,
            action_params={
                "id": ticket_id,
                "status": final_status or "N/A",
                "amount": amount,
                "email": email or "N/A",
            },
        )

    @classmethod
    def _build_ticket_summary(cls, body: dict):
        ticket_id = str(body.get("ticketId") or "").strip()
        status = str(body.get("status") or "").strip().lower()
        reject_reason = str(body.get("rejectReason") or "").strip()

        ticket = cls._find_ticket_by_id(ticket_id)
        order_id = str(ticket.get("orderId") or "").strip() if ticket else ""
        email = cls._get_user_email_by_customer_id(ticket.get("id_khach_hang")) if ticket else ""

        if status == "rejected":
            reason_text = reject_reason or (str(ticket.get("rejectReason") or "").strip() if ticket else "")
            return cls._build_action_payload(
                "logRejectComplaintDetailed",
                f"Reject complaint {ticket_id} | order: {order_id or 'N/A'} | email: {email or 'N/A'} | reason: {reason_text or 'N/A'}",
                action_status="Rejected",
                action_params={
                    "id": ticket_id,
                    "orderId": order_id or "N/A",
                    "email": email or "N/A",
                    "reason": reason_text or "N/A",
                },
            )

        if status in ["resolved", "approved"]:
            return cls._build_action_payload(
                "logResolveComplaintDetailed",
                f"Resolve complaint {ticket_id} | order: {order_id or 'N/A'} | email: {email or 'N/A'}",
                action_status=status.capitalize(),
                action_params={
                    "id": ticket_id,
                    "orderId": order_id or "N/A",
                    "email": email or "N/A",
                },
            )

        return cls._build_action_payload(
            "logUpdateTicket",
            f"Update complaint {ticket_id} | order: {order_id or 'N/A'} | email: {email or 'N/A'} | status: {status or 'N/A'}",
            action_status=status.capitalize() if status else None,
            action_params={
                "id": ticket_id,
                "orderId": order_id or "N/A",
                "email": email or "N/A",
                "status": status or "N/A",
            },
        )

    @classmethod
    def _build_product_add_summary(cls, body: dict):
        product_id = str(body.get("id") or body.get("productId") or "").strip()
        title = str(body.get("title") or "").strip()
        return cls._build_action_payload(
            "logAddProductDetailed",
            f"Add product {product_id or 'N/A'} | title: {title or 'N/A'}",
            action_params={
                "id": product_id or "N/A",
                "title": title or "N/A",
            },
        )

    @classmethod
    def _build_product_update_summary(cls, path: str):
        identifier = cls._extract_path_id(path, r"/api/products/([^/]+)$")
        product = cls._find_product_by_identifier(identifier)
        product_id = str(product.get("productId") or identifier or "N/A") if product else (identifier or "N/A")
        title = str(product.get("title") or "").strip() if product else "N/A"

        return cls._build_action_payload(
            "logUpdateProductDetailed",
            f"Update product {product_id} | title: {title}",
            action_params={
                "id": product_id,
                "title": title or "N/A",
            },
        )

    @classmethod
    def _build_product_delete_summary(cls, path: str):
        identifier = cls._extract_path_id(path, r"/api/products/([^/]+)$")
        product = cls._find_product_by_identifier(identifier)
        product_id = str(product.get("productId") or identifier or "N/A") if product else (identifier or "N/A")
        title = str(product.get("title") or "").strip() if product else "N/A"

        return cls._build_action_payload(
            "logDeleteProductDetailed",
            f"Delete product {product_id} | title: {title}",
            action_params={
                "id": product_id,
                "title": title or "N/A",
            },
        )

    @classmethod
    def _build_category_add_summary(cls, body: dict):
        category_id = str(body.get("slug") or body.get("name") or "").strip()
        name = str(body.get("name") or "").strip()
        return cls._build_action_payload(
            "logAddCategoryDetailed",
            f"Add category {category_id or 'N/A'} | name: {name or 'N/A'}",
            action_params={
                "id": category_id or "N/A",
                "name": name or "N/A",
            },
        )

    @classmethod
    def _build_category_update_summary(cls, path: str, body: dict):
        identifier = cls._extract_path_id(path, r"/api/admin/categories/([^/]+)$")
        category = cls._find_category_by_identifier(identifier)

        category_id = ""
        if category:
            category_id = str(category.get("_id") or category.get("slug") or identifier or "N/A")
        else:
            category_id = identifier or str(body.get("slug") or "") or "N/A"

        name = str((body.get("name") or (category.get("name") if category else "")) or "").strip()

        return cls._build_action_payload(
            "logUpdateCategoryDetailed",
            f"Update category {category_id} | name: {name or 'N/A'}",
            action_params={
                "id": category_id,
                "name": name or "N/A",
            },
        )

    @classmethod
    def _build_category_delete_summary(cls, path: str):
        identifier = cls._extract_path_id(path, r"/api/admin/categories/([^/]+)$")
        category = cls._find_category_by_identifier(identifier)
        category_id = str(category.get("_id") or category.get("slug") or identifier or "N/A") if category else (identifier or "N/A")
        name = str(category.get("name") or "").strip() if category else "N/A"

        return cls._build_action_payload(
            "logDeleteCategoryDetailed",
            f"Delete category {category_id} | name: {name}",
            action_params={
                "id": category_id,
                "name": name or "N/A",
            },
        )

    @classmethod
    def _build_staff_add_summary(cls, body: dict):
        email = str(body.get("email") or "").strip()
        name = str(body.get("name") or "").strip()
        permissions = cls._format_permissions(body.get("permissions"))

        staff = users_collection.find_one({"email": email, "role": "staff"})
        staff_id = ""
        if staff:
            staff_id = str(staff.get("_id") or staff.get("id") or "").strip()

        return cls._build_action_payload(
            "logAddStaffDetailed",
            f"Add staff {staff_id or 'N/A'} | email: {email or 'N/A'} | name: {name or 'N/A'} | permissions: {permissions}",
            action_params={
                "id": staff_id or "N/A",
                "email": email or "N/A",
                "name": name or "N/A",
                "permissions": permissions,
            },
        )

    @classmethod
    def _build_staff_update_summary(cls, body: dict):
        staff_id = str(body.get("staffId") or "").strip()
        email = str(body.get("email") or "").strip()
        status = str(body.get("status") or "").strip()
        permissions = cls._format_permissions(body.get("permissions"))

        staff = cls._find_staff_by_identifier(staff_id)
        if staff and not email:
            email = str(staff.get("email") or "").strip()

        return cls._build_action_payload(
            "logUpdateStaffDetailed",
            f"Update staff {staff_id or 'N/A'} | email: {email or 'N/A'} | status: {status or 'N/A'} | permissions: {permissions}",
            action_params={
                "id": staff_id or "N/A",
                "email": email or "N/A",
                "status": status or "N/A",
                "permissions": permissions,
            },
        )

    @classmethod
    def _build_staff_reset_password_summary(cls, body: dict):
        staff_id = str(body.get("staffId") or "").strip()
        staff = cls._find_staff_by_identifier(staff_id)
        email = str(staff.get("email") or "").strip() if staff else ""

        return cls._build_action_payload(
            "logResetStaffPasswordDetailed",
            f"Reset password for staff {staff_id or 'N/A'} | email: {email or 'N/A'}",
            action_params={
                "id": staff_id or "N/A",
                "email": email or "N/A",
            },
        )

    @classmethod
    def _build_change_password_summary(cls, body: dict):
        staff_id = str(body.get("staffId") or "").strip()
        staff = cls._find_staff_by_identifier(staff_id)
        email = str(staff.get("email") or "").strip() if staff else ""

        return cls._build_action_payload(
            "logChangePasswordDetailed",
            f"Change password | staff: {staff_id or 'N/A'} | email: {email or 'N/A'}",
            action_params={
                "id": staff_id or "N/A",
                "email": email or "N/A",
            },
        )

    @classmethod
    def _build_banner_update_summary(cls, body: dict):
        banner_id = str(body.get("bannerId") or "").strip()
        title = str(body.get("title") or "").strip()

        if not title and banner_id:
            banner = cls._find_banner_by_identifier(banner_id)
            if banner:
                title = str(banner.get("title") or "").strip()

        return cls._build_action_payload(
            "logUpdateBannerDetailed",
            f"Update banner {banner_id or 'N/A'} | title: {title or 'N/A'}",
            action_params={
                "id": banner_id or "N/A",
                "title": title or "N/A",
            },
        )

    @classmethod
    def _build_import_orders_summary(cls, body: dict):
        file_name = str(body.get("fileName") or "").strip()
        rows = body.get("rows")
        row_count = len(rows) if isinstance(rows, list) else 0

        return cls._build_action_payload(
            "logImportOrdersDetailed",
            f"Import orders | file: {file_name or 'N/A'} | rows: {row_count}",
            action_rows=row_count if row_count > 0 else None,
            action_params={
                "fileName": file_name or "N/A",
                "rows": row_count,
            },
        )

    @classmethod
    def _build_action_info(cls, row: dict):
        method = str(row.get("method", "") or "").upper()
        path = str(row.get("path", "") or "")
        body = cls._safe_body(row)
        required_permission = str(row.get("requiredPermission", "") or "").strip()

        if method == "PUT" and path == "/api/orders/admin/batch-status":
            return cls._build_order_batch_summary(body)

        if method == "PUT" and re.search(r"/api/orders/admin/[^/]+/status$", path):
            return cls._build_order_single_status_summary(path, body)

        if method == "POST" and re.search(r"/api/orders/admin/[^/]+/cancel$", path):
            return cls._build_order_cancel_summary(path)

        if method == "POST" and path == "/api/orders/pay":
            order_ids = body.get("orderIds") if isinstance(body.get("orderIds"), list) else []
            ids_text = cls._short_join(order_ids)
            count = len(order_ids) or 1
            return cls._build_action_payload(
                "logPayOrdersDetailed",
                f"Pay {count} order(s) | IDs: {ids_text}",
                action_count=count,
                action_params={
                    "count": count,
                    "ids": ids_text,
                },
            )

        if method == "POST" and path == "/api/import/orders":
            return cls._build_import_orders_summary(body)

        if method == "PUT" and path == "/api/topups/update-ticket":
            return cls._build_topup_summary(body)

        if method == "PUT" and path == "/api/tickets/update-ticket":
            return cls._build_ticket_summary(body)

        if method == "PUT" and path == "/api/update-banner":
            return cls._build_banner_update_summary(body)

        if method == "POST" and path == "/api/admin/add-product":
            return cls._build_product_add_summary(body)

        if method == "PUT" and path.startswith("/api/products/"):
            return cls._build_product_update_summary(path)

        if method == "DELETE" and path.startswith("/api/products/"):
            return cls._build_product_delete_summary(path)

        if method == "POST" and path == "/api/admin/categories":
            return cls._build_category_add_summary(body)

        if method == "PUT" and path.startswith("/api/admin/categories/"):
            return cls._build_category_update_summary(path, body)

        if method == "DELETE" and path.startswith("/api/admin/categories/"):
            return cls._build_category_delete_summary(path)

        if method == "POST" and path == "/api/add-staff":
            return cls._build_staff_add_summary(body)

        if method == "PUT" and path == "/api/update-staff":
            return cls._build_staff_update_summary(body)

        if method == "POST" and path == "/api/reset-password":
            return cls._build_staff_reset_password_summary(body)

        if method == "PUT" and path == "/api/change-password":
            return cls._build_change_password_summary(body)

        permission_map = {
            "order_operations": ("logOrderOperation", "Order operation"),
            "order_search": ("logOrderSearchAction", "Order search"),
            "audit_logs": ("logAuditLogsAction", "View action logs"),
        }

        if required_permission in permission_map:
            action_key, action_summary = permission_map[required_permission]
            return cls._build_action_payload(action_key, action_summary)

        if required_permission:
            return cls._build_action_payload(required_permission, required_permission)

        if method and path:
            return cls._build_action_payload("logActionSystem", f"{method} {path}")

        return cls._build_action_payload("logActionSystem", "System action")

    @classmethod
    def _matches_keyword(cls, row: dict, keyword: str):
        if not keyword:
            return True

        normalized_keyword = cls._normalize_search_text(keyword)
        if not normalized_keyword:
            return True

        haystacks = [
            str(row.get("actorName", "") or ""),
            str(row.get("actorRole", "") or ""),
            str(row.get("requiredPermission", "") or ""),
            str(row.get("actionSummary", "") or ""),
            str(row.get("actionKey", "") or ""),
            str(row.get("actionStatus", "") or ""),
            str(row.get("path", "") or ""),
        ]

        action_params = row.get("actionParams")
        if isinstance(action_params, dict):
            haystacks.extend([str(v or "") for v in action_params.values()])

        combined = " ".join(haystacks)
        normalized_combined = cls._normalize_search_text(combined)

        return normalized_keyword in normalized_combined

    @classmethod
    def get_logs(
        cls,
        page: int = 1,
        page_size: int = 15,
        method: str | None = None,
        outcome: str | None = None,
        actor_name: str | None = None,
        path: str | None = None,
        date_from: str | None = None,
        date_to: str | None = None,
    ):
        page = max(1, int(page))
        page_size = max(1, min(100, int(page_size)))

        query = {
            "actorRole": {"$in": ALLOWED_ACTOR_ROLES},
            "actorId": {"$nin": [None, ""]},
        }

        if method and method.lower() != "all":
            query["method"] = method.upper()

        if outcome and outcome.lower() != "all":
            query["outcome"] = outcome

        if path:
            query["path"] = {"$regex": path, "$options": "i"}

        if date_from or date_to:
            created_query = {}
            if date_from:
                created_query["$gte"] = date_from
            if date_to:
                created_query["$lte"] = f"{date_to}T23:59:59.999Z"
            query["createdAt"] = created_query

        rows = list(
            collection.find(query, {"_id": 0})
            .sort("createdAt", -1)
        )

        normalized_rows = []
        for row in rows:
            action_info = cls._build_action_info(row)
            merged = {
                **row,
                **action_info,
            }

            if cls._matches_keyword(merged, actor_name or ""):
                normalized_rows.append(merged)

        total = len(normalized_rows)
        start = (page - 1) * page_size
        end = start + page_size
        paged_rows = normalized_rows[start:end]

        return {
            "data": paged_rows,
            "total": total,
            "page": page,
            "pageSize": page_size,
            "totalPages": (total + page_size - 1) // page_size if total > 0 else 1,
        }