from fastapi import APIRouter, Depends, HTTPException, Query

from ntrp.memory.service import MemoryService
from ntrp.server.runtime import Runtime, get_runtime
from ntrp.server.schemas import UpdateFactRequest, UpdateObservationRequest

router = APIRouter(tags=["data"])


def _require_memory(runtime: Runtime = Depends(get_runtime)) -> MemoryService:
    if not runtime.memory_service:
        raise HTTPException(status_code=503, detail="Memory is disabled")
    return runtime.memory_service


@router.get("/facts")
async def get_facts(
    limit: int = Query(default=100, ge=1, le=500),
    offset: int = Query(default=0, ge=0),
    svc: MemoryService = Depends(_require_memory),
):
    facts, total = await svc.facts.list_recent(limit=limit, offset=offset)
    return {
        "facts": [
            {
                "id": f.id,
                "text": f.text,
                "source_type": f.source_type,
                "created_at": f.created_at.isoformat(),
            }
            for f in facts
        ],
        "total": total,
    }


@router.get("/facts/{fact_id}")
async def get_fact_details(fact_id: int, svc: MemoryService = Depends(_require_memory)):
    try:
        fact, entity_refs = await svc.facts.get(fact_id)
    except KeyError:
        raise HTTPException(status_code=404, detail="Fact not found")

    return {
        "fact": {
            "id": fact.id,
            "text": fact.text,
            "source_type": fact.source_type,
            "source_ref": fact.source_ref,
            "created_at": fact.created_at.isoformat(),
            "access_count": fact.access_count,
        },
        "entities": [{"name": e.name, "entity_id": e.entity_id} for e in entity_refs],
        "linked_facts": [],
    }


@router.patch("/facts/{fact_id}")
async def update_fact(fact_id: int, request: UpdateFactRequest, svc: MemoryService = Depends(_require_memory)):
    try:
        fact, entity_refs = await svc.facts.update(fact_id, request.text)
    except KeyError:
        raise HTTPException(status_code=404, detail="Fact not found")

    return {
        "fact": {
            "id": fact.id,
            "text": fact.text,
            "source_type": fact.source_type,
            "source_ref": fact.source_ref,
            "created_at": fact.created_at.isoformat(),
            "access_count": fact.access_count,
        },
        "entity_refs": entity_refs,
    }


@router.delete("/facts/{fact_id}")
async def delete_fact(fact_id: int, svc: MemoryService = Depends(_require_memory)):
    try:
        cascaded = await svc.facts.delete(fact_id)
    except KeyError:
        raise HTTPException(status_code=404, detail="Fact not found")

    return {
        "status": "deleted",
        "fact_id": fact_id,
        "cascaded": cascaded,
    }


@router.get("/observations")
async def get_observations(
    limit: int = Query(default=50, ge=1, le=500),
    svc: MemoryService = Depends(_require_memory),
):
    observations = await svc.observations.list_recent(limit=limit)
    return {
        "observations": [
            {
                "id": o.id,
                "summary": o.summary,
                "evidence_count": o.evidence_count,
                "access_count": o.access_count,
                "created_at": o.created_at.isoformat(),
                "updated_at": o.updated_at.isoformat(),
            }
            for o in observations
        ],
    }


@router.get("/observations/{observation_id}")
async def get_observation_details(observation_id: int, svc: MemoryService = Depends(_require_memory)):
    try:
        obs, facts = await svc.observations.get(observation_id)
    except KeyError:
        raise HTTPException(status_code=404, detail="Observation not found")

    return {
        "observation": {
            "id": obs.id,
            "summary": obs.summary,
            "evidence_count": obs.evidence_count,
            "access_count": obs.access_count,
            "created_at": obs.created_at.isoformat(),
            "updated_at": obs.updated_at.isoformat(),
        },
        "supporting_facts": [{"id": f.id, "text": f.text} for f in facts],
    }


@router.patch("/observations/{observation_id}")
async def update_observation(
    observation_id: int, request: UpdateObservationRequest, svc: MemoryService = Depends(_require_memory)
):
    try:
        obs = await svc.observations.update(observation_id, request.summary)
    except KeyError:
        raise HTTPException(status_code=404, detail="Observation not found")

    return {
        "observation": {
            "id": obs.id,
            "summary": obs.summary,
            "evidence_count": obs.evidence_count,
            "access_count": obs.access_count,
            "created_at": obs.created_at.isoformat(),
            "updated_at": obs.updated_at.isoformat(),
        }
    }


@router.delete("/observations/{observation_id}")
async def delete_observation(observation_id: int, svc: MemoryService = Depends(_require_memory)):
    try:
        await svc.observations.delete(observation_id)
    except KeyError:
        raise HTTPException(status_code=404, detail="Observation not found")

    return {
        "status": "deleted",
        "observation_id": observation_id,
    }


@router.get("/dreams")
async def get_dreams(
    limit: int = Query(default=50, ge=1, le=500),
    svc: MemoryService = Depends(_require_memory),
):
    dreams = await svc.dreams.list_recent(limit=limit)
    return {
        "dreams": [
            {
                "id": d.id,
                "bridge": d.bridge,
                "insight": d.insight,
                "created_at": d.created_at.isoformat(),
            }
            for d in dreams
        ],
    }


@router.get("/dreams/{dream_id}")
async def get_dream_details(dream_id: int, svc: MemoryService = Depends(_require_memory)):
    try:
        dream, source_facts = await svc.dreams.get(dream_id)
    except KeyError:
        raise HTTPException(status_code=404, detail="Dream not found")

    return {
        "dream": {
            "id": dream.id,
            "bridge": dream.bridge,
            "insight": dream.insight,
            "created_at": dream.created_at.isoformat(),
        },
        "source_facts": [{"id": f.id, "text": f.text} for f in source_facts],
    }


@router.delete("/dreams/{dream_id}")
async def delete_dream(dream_id: int, svc: MemoryService = Depends(_require_memory)):
    try:
        await svc.dreams.delete(dream_id)
    except KeyError:
        raise HTTPException(status_code=404, detail="Dream not found")

    return {"status": "deleted", "dream_id": dream_id}


@router.get("/stats")
async def get_stats(svc: MemoryService = Depends(_require_memory)):
    return await svc.stats()


@router.post("/memory/clear")
async def clear_memory(svc: MemoryService = Depends(_require_memory)):
    deleted = await svc.clear()
    return {"status": "cleared", "deleted": deleted}


@router.post("/memory/observations/clear")
async def clear_observations(svc: MemoryService = Depends(_require_memory)):
    result = await svc.clear_observations()
    return {"status": "cleared", **result}
