"""Operation repository for database operations on operations."""
from datetime import UTC, datetime
from typing import Optional

from bson import ObjectId

from app.db import Database
from app.models.operation import Operation

COL = "operations"


def create(operation: Operation) -> Operation:
    """Create a new operation record in the database."""
    now = datetime.now(UTC)
    operation_to_insert = operation.model_copy(
        update={"created_at": now, "updated_at": now}
    ).to_bson()
    res = Database.get_db().get_collection(COL).insert_one(operation_to_insert)
    return Operation.from_bson({**operation_to_insert, "_id": res.inserted_id})


def find_by_id(operation_id: str) -> Optional[Operation]:
    """Find an operation record by its ID."""
    if not ObjectId.is_valid(operation_id):
        return None
    doc = Database.get_db().get_collection(COL).find_one({"_id": ObjectId(operation_id)})
    return Operation.from_bson(doc) if doc else None


def find_by_patient_id(patient_id: str) -> list[Operation]:
    """Find all operations for a patient."""
    if not ObjectId.is_valid(patient_id):
        raise ValueError("Invalid patient ID")
    docs = Database.get_db().get_collection(COL).find({"patientId": ObjectId(patient_id)})
    return [Operation.from_bson(doc) for doc in docs]


def update(operation_id: str, updates: dict) -> Optional[Operation]:
    """Update an operation record."""
    if not ObjectId.is_valid(operation_id):
        return None
    db = Database.get_db()
    existing = db.get_collection(COL).find_one({"_id": ObjectId(operation_id)})
    if not existing:
        return None

    # Merge existing document with updates, validate via model,
    # and ensure updated_at is refreshed.
    merged = {**existing, **updates}
    candidate = Operation.from_bson(merged).model_copy(update={"updated_at": datetime.now(UTC)})
    to_set = candidate.to_bson()
    to_set.pop("_id", None)

    doc = db.get_collection(COL).find_one_and_update(
        {"_id": ObjectId(operation_id)},
        {"$set": to_set},
    )
    return Operation.from_bson(doc) if doc else None
