"""Admin-only user CRUD + settings."""
import uuid
from datetime import datetime, timedelta, timezone
from typing import List, Optional

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, Field
from sqlalchemy import select
from sqlalchemy.orm import Session

from core.auth import hash_password, require_admin
from db.models import Setting, User
from db.session import get_session
from routes.auth import shape_user

router = APIRouter(prefix="/api/admin", tags=["admin"], dependencies=[Depends(require_admin)])


# ---- User models ----
class UserCreate(BaseModel):
    username: str = Field(min_length=2, max_length=40)
    password: str = Field(min_length=3, max_length=200)
    days: int = Field(default=30, ge=1, le=3650)
    xtream_mode: str = Field(default="shared", pattern="^(shared|own)$")
    xtream_server: Optional[str] = None
    xtream_username: Optional[str] = None
    xtream_password: Optional[str] = None
    note: Optional[str] = None


class UserUpdate(BaseModel):
    password: Optional[str] = Field(default=None, min_length=3, max_length=200)
    extend_days: Optional[int] = Field(default=None, ge=-3650, le=3650)
    set_expiry_at: Optional[str] = None
    xtream_mode: Optional[str] = Field(default=None, pattern="^(shared|own)$")
    xtream_server: Optional[str] = None
    xtream_username: Optional[str] = None
    xtream_password: Optional[str] = None
    note: Optional[str] = None


class SharedProfileIn(BaseModel):
    id: Optional[str] = None
    name: str
    kind: str = Field(pattern="^(xtream|m3u)$")
    server: Optional[str] = ""
    username: Optional[str] = ""
    password: Optional[str] = ""
    m3u_url: Optional[str] = ""


class SettingsUpdate(BaseModel):
    whatsapp_number: Optional[str] = None
    shared_xtream_server: Optional[str] = None
    shared_xtream_username: Optional[str] = None
    shared_xtream_password: Optional[str] = None
    shared_profiles: Optional[List[SharedProfileIn]] = None
    external_player_enabled: Optional[bool] = None
    inline_preview_enabled: Optional[bool] = None


SETTINGS_ID = "global"
DEFAULT_SETTINGS = {
    "whatsapp_number": "+1234567890",
    "shared_xtream_server": "",
    "shared_xtream_username": "",
    "shared_xtream_password": "",
    "shared_profiles": [],
    "external_player_enabled": False,
    "inline_preview_enabled": True,
}


def get_settings_doc(db: Session) -> dict:
    row = db.get(Setting, SETTINGS_ID)
    if not row:
        row = Setting(id=SETTINGS_ID, data=dict(DEFAULT_SETTINGS))
        db.add(row)
        db.commit()
    data = dict(row.data or {})
    # Backfill any newly-added keys
    changed = False
    for k, v in DEFAULT_SETTINGS.items():
        if k not in data:
            data[k] = v
            changed = True
    if changed:
        row.data = data
        db.commit()
    data["id"] = SETTINGS_ID
    return data


# ---- User endpoints ----
@router.get("/users")
def list_users(db: Session = Depends(get_session)):
    rows = db.scalars(select(User).where(User.role == "user")).all()
    return [shape_user(r.as_dict()) for r in rows]


@router.post("/users")
def create_user(body: UserCreate, db: Session = Depends(get_session)):
    username = body.username.strip().lower()
    if db.scalar(select(User).where(User.username == username)):
        raise HTTPException(status_code=409, detail="Username already exists")
    now = datetime.now(timezone.utc)
    expiry = now + timedelta(days=body.days)
    u = User(
        id=str(uuid.uuid4()),
        username=username,
        password_hash=hash_password(body.password),
        role="user",
        created_at=now.isoformat(),
        expiry_at=expiry.isoformat(),
        xtream_mode=body.xtream_mode,
        xtream_server=body.xtream_server or "",
        xtream_username=body.xtream_username or "",
        xtream_password=body.xtream_password or "",
        note=body.note or "",
    )
    db.add(u)
    db.commit()
    return shape_user(u.as_dict())


@router.put("/users/{user_id}")
def update_user(user_id: str, body: UserUpdate, db: Session = Depends(get_session)):
    u = db.scalar(select(User).where(User.id == user_id, User.role == "user"))
    if not u:
        raise HTTPException(status_code=404, detail="User not found")

    if body.password is not None:
        u.password_hash = hash_password(body.password)
    if body.set_expiry_at is not None:
        try:
            datetime.fromisoformat(body.set_expiry_at)
        except Exception:
            raise HTTPException(status_code=400, detail="Invalid set_expiry_at")
        u.expiry_at = body.set_expiry_at
    if body.extend_days is not None:
        base_iso = u.expiry_at
        try:
            base = datetime.fromisoformat(base_iso) if base_iso else datetime.now(timezone.utc)
        except Exception:
            base = datetime.now(timezone.utc)
        if base.tzinfo is None:
            base = base.replace(tzinfo=timezone.utc)
        if base < datetime.now(timezone.utc):
            base = datetime.now(timezone.utc)
        u.expiry_at = (base + timedelta(days=body.extend_days)).isoformat()
    for field in ("xtream_mode", "xtream_server", "xtream_username", "xtream_password", "note"):
        val = getattr(body, field)
        if val is not None:
            setattr(u, field, val)

    db.commit()
    return shape_user(u.as_dict())


@router.delete("/users/{user_id}")
def delete_user(user_id: str, db: Session = Depends(get_session)):
    u = db.scalar(select(User).where(User.id == user_id, User.role == "user"))
    if not u:
        raise HTTPException(status_code=404, detail="User not found")
    db.delete(u)
    db.commit()
    return {"ok": True}


# ---- Settings endpoints ----
@router.get("/settings")
def get_settings(db: Session = Depends(get_session)):
    return get_settings_doc(db)


@router.put("/settings")
def put_settings(body: SettingsUpdate, db: Session = Depends(get_session)):
    get_settings_doc(db)  # ensure row exists
    row = db.get(Setting, SETTINGS_ID)
    data = dict(row.data or {})
    raw = body.model_dump()
    for k, v in raw.items():
        if v is None:
            continue
        if k == "shared_profiles":
            cleaned = []
            for p in v:
                cleaned.append({
                    "id": p.get("id") or str(uuid.uuid4()),
                    "name": (p.get("name") or "").strip() or "Profile",
                    "kind": p.get("kind") or "xtream",
                    "server": (p.get("server") or "").strip(),
                    "username": (p.get("username") or "").strip(),
                    "password": p.get("password") or "",
                    "m3u_url": (p.get("m3u_url") or "").strip(),
                })
            data["shared_profiles"] = cleaned
        else:
            data[k] = v
    row.data = data
    # Force JSON mutation detection in SQLAlchemy (mutable dict not always flagged)
    from sqlalchemy.orm.attributes import flag_modified
    flag_modified(row, "data")
    db.commit()
    out = dict(row.data)
    out["id"] = SETTINGS_ID
    return out
