"""Graph preset repository for database operations."""
from datetime import UTC, datetime
from typing import Optional

from bson import ObjectId
from pymongo import ReturnDocument

from app.db import Database
from app.models.graph_preset import GraphPreset

COL = "graph_presets"


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


def find_by_patient_id(patient_id: str) -> list[GraphPreset]:
    """Find all graph presets 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)})
        .sort("updated_at", -1)
    )
    return [GraphPreset.from_bson(doc) for doc in docs]


def find_by_id(graph_preset_id: str) -> Optional[GraphPreset]:
    """Find a graph preset by its ID."""
    if not ObjectId.is_valid(graph_preset_id):
        return None

    doc = Database.get_db().get_collection(COL).find_one({"_id": ObjectId(graph_preset_id)})
    return GraphPreset.from_bson(doc) if doc else None


def update(graph_preset_id: str, updates: dict) -> Optional[GraphPreset]:
    """Update an existing graph preset."""
    if not ObjectId.is_valid(graph_preset_id):
        raise ValueError("Invalid graph preset ID")

    db = Database.get_db()
    existing = db.get_collection(COL).find_one({"_id": ObjectId(graph_preset_id)})
    if not existing:
        return None

    merged = {**existing, **updates}
    candidate = GraphPreset.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(graph_preset_id)},
        {"$set": to_set},
        return_document=ReturnDocument.AFTER,
    )
    return GraphPreset.from_bson(doc) if doc else None


def delete(graph_preset_id: str) -> bool:
    """Delete a graph preset by ID."""
    if not ObjectId.is_valid(graph_preset_id):
        return False

    res = Database.get_db().get_collection(COL).delete_one({"_id": ObjectId(graph_preset_id)})
    return res.deleted_count == 1


def delete_by_patient_id(patient_id: str) -> int:
    """Delete all graph presets for a patient and return the deleted count."""
    if not ObjectId.is_valid(patient_id):
        raise ValueError("Invalid patient ID")

    result = Database.get_db().get_collection(COL).delete_many({"patientId": ObjectId(patient_id)})
    return result.deleted_count
