"""
Dashboard Notes API - Team notes, pinned docs, draft management.
Stores notes in a local JSON file for simplicity.
"""
import json
import os
import uuid
from datetime import datetime
from typing import Optional
from pathlib import Path

from fastapi import APIRouter, Header, HTTPException
from pydantic import BaseModel

router = APIRouter(prefix="/api/dashboard", tags=["Dashboard Notes"])

# Storage path
NOTES_FILE = Path(__file__).parent.parent / "data" / "dashboard_notes.json"


class NoteCreate(BaseModel):
    title: str
    content: str
    category: str = "note"  # note, doc, todo, announcement
    pinned: bool = False
    color: Optional[str] = None  # optional color tag


class NoteUpdate(BaseModel):
    title: Optional[str] = None
    content: Optional[str] = None
    category: Optional[str] = None
    pinned: Optional[bool] = None
    color: Optional[str] = None


def _load_notes() -> list:
    """Load notes from JSON file."""
    if not NOTES_FILE.exists():
        NOTES_FILE.parent.mkdir(parents=True, exist_ok=True)
        NOTES_FILE.write_text("[]", encoding="utf-8")
        return []
    try:
        return json.loads(NOTES_FILE.read_text(encoding="utf-8"))
    except (json.JSONDecodeError, FileNotFoundError):
        return []


def _save_notes(notes: list):
    """Save notes to JSON file."""
    NOTES_FILE.parent.mkdir(parents=True, exist_ok=True)
    NOTES_FILE.write_text(json.dumps(notes, ensure_ascii=False, indent=2), encoding="utf-8")


@router.get("/notes")
async def list_notes():
    """Get all notes, pinned first."""
    notes = _load_notes()
    # Sort: pinned first, then by updated_at desc
    notes.sort(key=lambda n: (not n.get("pinned", False), n.get("updated_at", "")), reverse=False)
    notes.sort(key=lambda n: (not n.get("pinned", False)))
    return {"status": "success", "notes": notes, "total": len(notes)}


@router.post("/notes")
async def create_note(note: NoteCreate, x_author: str = Header(default="Admin")):
    """Create a new note."""
    notes = _load_notes()
    now = datetime.now().isoformat()
    new_note = {
        "id": str(uuid.uuid4())[:8],
        "title": note.title,
        "content": note.content,
        "category": note.category,
        "pinned": note.pinned,
        "color": note.color or _default_color(note.category),
        "created_at": now,
        "updated_at": now,
        "author": x_author,
    }
    notes.append(new_note)
    _save_notes(notes)
    return {"status": "success", "note": new_note}


@router.put("/notes/{note_id}")
async def update_note(note_id: str, update: NoteUpdate, x_author: str = Header(default="Admin")):
    """Update an existing note. Only the original author can edit."""
    notes = _load_notes()
    for i, n in enumerate(notes):
        if n["id"] == note_id:
            if n.get("author", "Admin") != x_author and x_author != "Admin":
                raise HTTPException(status_code=403, detail=f"Bạn không thể sửa note của {n.get('author')}")
            if update.title is not None:
                notes[i]["title"] = update.title
            if update.content is not None:
                notes[i]["content"] = update.content
            if update.category is not None:
                notes[i]["category"] = update.category
            if update.pinned is not None:
                notes[i]["pinned"] = update.pinned
            if update.color is not None:
                notes[i]["color"] = update.color
            notes[i]["updated_at"] = datetime.now().isoformat()
            _save_notes(notes)
            return {"status": "success", "note": notes[i]}
    raise HTTPException(status_code=404, detail="Note not found")


@router.delete("/notes/{note_id}")
async def delete_note(note_id: str, x_author: str = Header(default="Admin")):
    """Delete a note. Only the original author can delete."""
    notes = _load_notes()
    for n in notes:
        if n["id"] == note_id:
            if n.get("author", "Admin") != x_author and x_author != "Admin":
                raise HTTPException(status_code=403, detail=f"Bạn không thể xóa note của {n.get('author')}")
            break
    original_len = len(notes)
    notes = [n for n in notes if n["id"] != note_id]
    if len(notes) == original_len:
        raise HTTPException(status_code=404, detail="Note not found")
    _save_notes(notes)
    return {"status": "success", "message": "Note deleted"}


@router.patch("/notes/{note_id}/pin")
async def toggle_pin(note_id: str):
    """Toggle pin status of a note."""
    notes = _load_notes()
    for i, n in enumerate(notes):
        if n["id"] == note_id:
            notes[i]["pinned"] = not notes[i].get("pinned", False)
            notes[i]["updated_at"] = datetime.now().isoformat()
            _save_notes(notes)
            return {"status": "success", "pinned": notes[i]["pinned"]}
    raise HTTPException(status_code=404, detail="Note not found")


def _default_color(category: str) -> str:
    """Return default color based on category."""
    return {
        "note": "#58a6ff",
        "doc": "#a78bfa",
        "todo": "#e3b341",
        "announcement": "#f85149",
    }.get(category, "#58a6ff")


# ═══════════════════════════════════════════════════
#  LINKS / RESOURCES
# ═══════════════════════════════════════════════════

LINKS_FILE = Path(__file__).parent.parent / "data" / "dashboard_links.json"


class LinkCreate(BaseModel):
    title: str
    url: str
    description: str = ""
    category: str = "other"  # tool, doc, design, api, repo, other
    icon: str = ""  # emoji icon
    pinned: bool = False


class LinkUpdate(BaseModel):
    title: Optional[str] = None
    url: Optional[str] = None
    description: Optional[str] = None
    category: Optional[str] = None
    icon: Optional[str] = None
    pinned: Optional[bool] = None


DEFAULT_TOOL_LINKS = [
    {"id": "tool_stress_test", "title": "Stress Test Dashboard", "url": "/static/stress-test.html",
     "description": "Bắn N request đồng thời — đo RPS, latency p95, error rate", "category": "tool", "icon": "🔥", "pinned": False, "author": "System"},
    {"id": "tool_regression_test", "title": "Regression Test", "url": "/static/regression-test.html",
     "description": "Chạy bộ test cases qua bất kỳ chatbot URL — con người đọc kết quả", "category": "tool", "icon": "🧪", "pinned": False, "author": "System"},
    {"id": "tool_user_simulator", "title": "User Simulator", "url": "/static/user-simulator.html",
     "description": "AI đóng vai persona test chatbot — đánh giá từ góc user thật", "category": "tool", "icon": "🎭", "pinned": False, "author": "System"},
    {"id": "tool_prompt_optimizer", "title": "Prompt Optimizer", "url": "/static/prompt-optimizer.html",
     "description": "AI Judge chấm điểm chatbot + tự động gợi ý cải thiện prompt", "category": "tool", "icon": "⚡", "pinned": False, "author": "System"},
    {"id": "tool_competitor_research", "title": "Competitor Research", "url": "/static/competitor-research.html",
     "description": "Nghiên cứu đối thủ — phân tích Zalando, YaMe, H&M", "category": "doc", "icon": "🔍", "pinned": False, "author": "System"},
]


def _load_links() -> list:
    if not LINKS_FILE.exists():
        LINKS_FILE.parent.mkdir(parents=True, exist_ok=True)
        LINKS_FILE.write_text("[]", encoding="utf-8")
        return []
    try:
        links = json.loads(LINKS_FILE.read_text(encoding="utf-8"))
    except (json.JSONDecodeError, FileNotFoundError):
        links = []

    # Auto-seed default tool links if missing
    existing_ids = {l.get("id") for l in links}
    added = False
    for default in DEFAULT_TOOL_LINKS:
        if default["id"] not in existing_ids:
            links.append({**default, "created_at": datetime.now().isoformat()})
            added = True
    if added:
        _save_links(links)

    return links


def _save_links(links: list):
    LINKS_FILE.parent.mkdir(parents=True, exist_ok=True)
    LINKS_FILE.write_text(json.dumps(links, ensure_ascii=False, indent=2), encoding="utf-8")


@router.get("/links")
async def list_links():
    """Get all resource links, pinned first."""
    links = _load_links()
    links.sort(key=lambda l: (not l.get("pinned", False), l.get("created_at", "")))
    return {"status": "success", "links": links, "total": len(links)}


@router.post("/links")
async def create_link(link: LinkCreate, x_author: str = Header(default="Admin")):
    """Create a new resource link."""
    links = _load_links()
    now = datetime.now().isoformat()
    new_link = {
        "id": str(uuid.uuid4())[:8],
        "title": link.title,
        "url": link.url,
        "description": link.description,
        "category": link.category,
        "icon": link.icon or _default_icon(link.category),
        "pinned": link.pinned,
        "created_at": now,
        "author": x_author,
    }
    links.append(new_link)
    _save_links(links)
    return {"status": "success", "link": new_link}


@router.put("/links/{link_id}")
async def update_link(link_id: str, update: LinkUpdate, x_author: str = Header(default="Admin")):
    """Update an existing resource link. Only original author can edit."""
    links = _load_links()
    for i, l in enumerate(links):
        if l["id"] == link_id:
            if l.get("author", "Admin") != x_author and x_author != "Admin":
                raise HTTPException(status_code=403, detail=f"Bạn không thể sửa link của {l.get('author')}")
            for field in ["title", "url", "description", "category", "icon", "pinned"]:
                val = getattr(update, field, None)
                if val is not None:
                    links[i][field] = val
            _save_links(links)
            return {"status": "success", "link": links[i]}
    raise HTTPException(status_code=404, detail="Link not found")


@router.delete("/links/{link_id}")
async def delete_link(link_id: str, x_author: str = Header(default="Admin")):
    """Delete a resource link. Only original author can delete."""
    links = _load_links()
    for l in links:
        if l["id"] == link_id:
            if l.get("author", "Admin") != x_author and x_author != "Admin":
                raise HTTPException(status_code=403, detail=f"Bạn không thể xóa link của {l.get('author')}")
            break
    original_len = len(links)
    links = [l for l in links if l["id"] != link_id]
    if len(links) == original_len:
        raise HTTPException(status_code=404, detail="Link not found")
    _save_links(links)
    return {"status": "success", "message": "Link deleted"}


@router.patch("/links/{link_id}/pin")
async def toggle_link_pin(link_id: str):
    """Toggle pin status of a link."""
    links = _load_links()
    for i, l in enumerate(links):
        if l["id"] == link_id:
            links[i]["pinned"] = not links[i].get("pinned", False)
            _save_links(links)
            return {"status": "success", "pinned": links[i]["pinned"]}
    raise HTTPException(status_code=404, detail="Link not found")


def _default_icon(category: str) -> str:
    return {
        "tool": "🔧",
        "doc": "📄",
        "design": "🎨",
        "api": "🔌",
        "repo": "📦",
        "other": "🔗",
    }.get(category, "🔗")


# ═══════════════════════════════════════════════════
#  CHANGELOG
# ═══════════════════════════════════════════════════
CHANGELOG_FILE = Path(__file__).parent.parent / "data" / "dashboard_changelog.json"

class ChangelogCreate(BaseModel):
    content: str
    author: str = "Admin"

def _load_changelog() -> list:
    if not CHANGELOG_FILE.exists():
        CHANGELOG_FILE.parent.mkdir(parents=True, exist_ok=True)
        CHANGELOG_FILE.write_text("[]", encoding="utf-8")
        return []
    try:
        return json.loads(CHANGELOG_FILE.read_text(encoding="utf-8"))
    except (json.JSONDecodeError, FileNotFoundError):
        return []


def _save_changelog(entries: list):
    CHANGELOG_FILE.parent.mkdir(parents=True, exist_ok=True)
    CHANGELOG_FILE.write_text(json.dumps(entries, ensure_ascii=False, indent=2), encoding="utf-8")


@router.get("/changelog")
async def list_changelog():
    """Get all changelog entries, newest first."""
    entries = _load_changelog()
    entries.sort(key=lambda e: e.get("created_at", ""), reverse=True)
    return {"status": "success", "entries": entries, "total": len(entries)}


@router.post("/changelog")
async def create_changelog_entry(entry: ChangelogCreate):
    """Add a new changelog entry."""
    entries = _load_changelog()
    new_entry = {
        "id": str(uuid.uuid4())[:8],
        "content": entry.content,
        "author": entry.author,
        "created_at": datetime.now().isoformat(),
    }
    entries.append(new_entry)
    _save_changelog(entries)
    return {"status": "success", "entry": new_entry}


@router.delete("/changelog/{entry_id}")
async def delete_changelog_entry(entry_id: str):
    """Delete a changelog entry."""
    entries = _load_changelog()
    original_len = len(entries)
    entries = [e for e in entries if e["id"] != entry_id]
    if len(entries) == original_len:
        raise HTTPException(status_code=404, detail="Entry not found")
    _save_changelog(entries)
    return {"status": "success", "message": "Entry deleted"}


# ═══════════════════════════════════════════════════
#  USERS / ROLES
# ═══════════════════════════════════════════════════
USERS_FILE = Path(__file__).parent.parent / "data" / "users.json"


def _load_users() -> list:
    if not USERS_FILE.exists():
        USERS_FILE.parent.mkdir(parents=True, exist_ok=True)
        USERS_FILE.write_text('[{"name":"Admin","role":"admin"}]', encoding="utf-8")
        return [{"name": "Admin", "role": "admin"}]
    try:
        return json.loads(USERS_FILE.read_text(encoding="utf-8"))
    except (json.JSONDecodeError, FileNotFoundError):
        return []


def _save_users(users: list):
    USERS_FILE.parent.mkdir(parents=True, exist_ok=True)
    USERS_FILE.write_text(json.dumps(users, ensure_ascii=False, indent=2), encoding="utf-8")


class UserCreate(BaseModel):
    name: str
    role: str = "user"  # admin | user


@router.get("/users")
async def list_users():
    """Get all users and their roles."""
    return {"status": "success", "users": _load_users()}


@router.post("/users")
async def add_user(user: UserCreate):
    """Add a new user role."""
    users = _load_users()
    # Update if exists
    for u in users:
        if u["name"].lower() == user.name.lower():
            u["role"] = user.role
            _save_users(users)
            return {"status": "success", "message": f"Updated {user.name} to {user.role}", "users": users}
    users.append({"name": user.name, "role": user.role})
    _save_users(users)
    return {"status": "success", "message": f"Added {user.name} as {user.role}", "users": users}


@router.delete("/users/{name}")
async def remove_user(name: str):
    """Remove a user role entry."""
    users = _load_users()
    users = [u for u in users if u["name"].lower() != name.lower()]
    _save_users(users)
    return {"status": "success", "users": users}