from datetime import datetime, timezone
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List

from database import get_db
from models.notes import SiteNote, SiteTodo
from models.user import User
from schemas.notes import NoteCreate, NoteUpdate, NoteOut, TodoCreate, TodoUpdate, TodoOut
from routers.deps import require_manager

router = APIRouter()


def _utcnow():
    return datetime.now(timezone.utc)


def _note_out(n: SiteNote) -> dict:
    name = None
    if n.created_by:
        name = n.created_by.full_name or n.created_by.username
    return {
        "id": n.id,
        "body": n.body,
        "is_pinned": n.is_pinned,
        "created_by_id": n.created_by_id,
        "created_by_name": name,
        "created_at": n.created_at,
        "updated_at": n.updated_at,
    }


def _todo_out(t: SiteTodo) -> dict:
    creator_name = None
    if t.created_by:
        creator_name = t.created_by.full_name or t.created_by.username
    done_name = None
    if t.done_by:
        done_name = t.done_by.full_name or t.done_by.username
    return {
        "id": t.id,
        "body": t.body,
        "is_done": t.is_done,
        "done_at": t.done_at,
        "done_by_id": t.done_by_id,
        "done_by_name": done_name,
        "created_by_id": t.created_by_id,
        "created_by_name": creator_name,
        "created_at": t.created_at,
        "priority": t.priority,
    }


# ── Notes ─────────────────────────────────────────────────────────────────────

@router.get("/", response_model=List[NoteOut])
def list_notes(db: Session = Depends(get_db), user: User = Depends(require_manager)):
    notes = db.query(SiteNote).order_by(
        SiteNote.is_pinned.desc(), SiteNote.updated_at.desc()
    ).all()
    return [_note_out(n) for n in notes]


@router.post("/", response_model=NoteOut, status_code=status.HTTP_201_CREATED)
def create_note(body: NoteCreate, db: Session = Depends(get_db), user: User = Depends(require_manager)):
    note = SiteNote(body=body.body, is_pinned=body.is_pinned, created_by_id=user.id)
    db.add(note)
    db.commit()
    db.refresh(note)
    return _note_out(note)


@router.put("/{note_id}", response_model=NoteOut)
def update_note(note_id: int, body: NoteUpdate, db: Session = Depends(get_db), user: User = Depends(require_manager)):
    note = db.query(SiteNote).filter(SiteNote.id == note_id).first()
    if not note:
        raise HTTPException(status_code=404, detail="Note not found")
    if body.body is not None:
        note.body = body.body
    if body.is_pinned is not None:
        note.is_pinned = body.is_pinned
    note.updated_at = _utcnow()
    db.commit()
    db.refresh(note)
    return _note_out(note)


@router.delete("/{note_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_note(note_id: int, db: Session = Depends(get_db), user: User = Depends(require_manager)):
    note = db.query(SiteNote).filter(SiteNote.id == note_id).first()
    if not note:
        raise HTTPException(status_code=404, detail="Note not found")
    db.delete(note)
    db.commit()


# ── Todos ─────────────────────────────────────────────────────────────────────

@router.get("/todos", response_model=List[TodoOut])
def list_todos(done: bool = None, db: Session = Depends(get_db), user: User = Depends(require_manager)):
    q = db.query(SiteTodo)
    if done is not None:
        q = q.filter(SiteTodo.is_done == done)
    # undone high-priority first, then undone normal, then done (by created_at desc)
    todos = q.order_by(
        SiteTodo.is_done.asc(),
        SiteTodo.priority.desc(),
        SiteTodo.created_at.desc(),
    ).all()
    return [_todo_out(t) for t in todos]


@router.post("/todos", response_model=TodoOut, status_code=status.HTTP_201_CREATED)
def create_todo(body: TodoCreate, db: Session = Depends(get_db), user: User = Depends(require_manager)):
    todo = SiteTodo(body=body.body, priority=body.priority, created_by_id=user.id)
    db.add(todo)
    db.commit()
    db.refresh(todo)
    return _todo_out(todo)


@router.put("/todos/{todo_id}", response_model=TodoOut)
def update_todo(todo_id: int, body: TodoUpdate, db: Session = Depends(get_db), user: User = Depends(require_manager)):
    todo = db.query(SiteTodo).filter(SiteTodo.id == todo_id).first()
    if not todo:
        raise HTTPException(status_code=404, detail="Todo not found")
    if body.body is not None:
        todo.body = body.body
    if body.priority is not None:
        todo.priority = body.priority
    if body.is_done is not None:
        todo.is_done = body.is_done
        if body.is_done and not todo.done_at:
            todo.done_at = _utcnow()
            todo.done_by_id = user.id
        elif not body.is_done:
            todo.done_at = None
            todo.done_by_id = None
    db.commit()
    db.refresh(todo)
    return _todo_out(todo)


@router.delete("/todos/{todo_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_todo(todo_id: int, db: Session = Depends(get_db), user: User = Depends(require_manager)):
    todo = db.query(SiteTodo).filter(SiteTodo.id == todo_id).first()
    if not todo:
        raise HTTPException(status_code=404, detail="Todo not found")
    db.delete(todo)
    db.commit()
