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

from bson import ObjectId

from app.db import Database
from app.models.prescription import Prescription

COL = "prescriptions"


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


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


def find_by_patient_id(patient_id: str) -> list[Prescription]:
    """Find all prescriptions 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 [Prescription.from_bson(doc) for doc in docs]


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

    # Merge existing document with updates, validate via model,
    # and ensure updated_at is refreshed.
    merged = {**existing, **updates}
    candidate = Prescription.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(prescription_id)},
        {"$set": to_set},
    )
    return Prescription.from_bson(doc) if doc else None


def delete(prescription_id: str) -> bool:
    """Delete a prescription record."""
    if not ObjectId.is_valid(prescription_id):
        return False
    res = Database.get_db().get_collection(COL).delete_one({"_id": ObjectId(prescription_id)})
    return res.deleted_count > 0
