from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, or_
from pydantic import BaseModel
from typing import Optional, List
from datetime import datetime
import re
import json as _json
import secrets

from app.api.deps import get_db, get_admin_user
from app.core.models.article import Article

router = APIRouter(prefix="/admin/articles", tags=["admin-articles"])


# ── Schemas ──────────────────────────────────────────────────────────────────

class ArticleBase(BaseModel):
    title:               str
    slug:                Optional[str]      = None
    content:             Optional[str]      = None
    excerpt:             Optional[str]      = None
    featured_image:      Optional[str]      = None
    status:              Optional[str]      = "draft"
    author_name:         Optional[str]      = None
    published_at:        Optional[datetime] = None
    seo_title:           Optional[str]      = None
    seo_description:     Optional[str]      = None
    seo_keywords:        Optional[str]      = None
    og_image:            Optional[str]      = None
    canonical_url:       Optional[str]      = None
    content_blocks:      Optional[List[dict]] = None
    # English fields
    title_en:            Optional[str]      = None
    content_en:          Optional[str]      = None
    excerpt_en:          Optional[str]      = None
    seo_title_en:        Optional[str]      = None
    seo_description_en:  Optional[str]      = None
    seo_keywords_en:     Optional[str]      = None


class ArticleCreate(ArticleBase):
    pass


class ArticleUpdate(ArticleBase):
    title: Optional[str] = None


class ArticleOut(BaseModel):
    id:              int
    tenant_id:       int
    title:           str
    slug:            str
    content:         Optional[str]
    excerpt:         Optional[str]
    featured_image:  Optional[str]
    status:          str
    author_name:     Optional[str]
    published_at:    Optional[datetime]
    view_count:      int
    seo_title:       Optional[str]
    seo_description: Optional[str]
    seo_keywords:    Optional[str]
    og_image:            Optional[str]
    canonical_url:       Optional[str]
    title_en:            Optional[str]      = None
    content_en:          Optional[str]      = None
    excerpt_en:          Optional[str]      = None
    seo_title_en:        Optional[str]      = None
    seo_description_en:  Optional[str]      = None
    seo_keywords_en:     Optional[str]      = None
    content_blocks:      Optional[List[dict]] = None
    preview_token:       Optional[str]      = None
    created_at:          Optional[datetime]
    updated_at:          Optional[datetime]

    model_config = {"from_attributes": True}


def _slugify(text: str) -> str:
    text = text.lower().strip()
    text = re.sub(r"[^\w\s-]", "", text)
    text = re.sub(r"[\s_-]+", "-", text)
    return text.strip("-") or "article"


class ArticleTranslateRequest(BaseModel):
    title:           Optional[str] = None
    content:         Optional[str] = None
    excerpt:         Optional[str] = None
    seo_title:       Optional[str] = None
    seo_description: Optional[str] = None
    seo_keywords:    Optional[str] = None

class ArticleTranslateResponse(BaseModel):
    title_en:           str = ""
    content_en:         str = ""
    excerpt_en:         str = ""
    seo_title_en:       str = ""
    seo_description_en: str = ""
    seo_keywords_en:    str = ""


class PreviewTokenResponse(BaseModel):
    token: str


# ── Routes ───────────────────────────────────────────────────────────────────

@router.post("/translate", response_model=ArticleTranslateResponse, summary="AI翻译文章字段")
async def translate_article(
    body: ArticleTranslateRequest,
    db: AsyncSession = Depends(get_db),
    admin = Depends(get_admin_user),
):
    from app.core.models.tenant_settings import TenantSettings
    from sqlalchemy import select as _select
    s_r = await db.execute(_select(TenantSettings).where(TenantSettings.tenant_id == admin.tenant_id))
    s = s_r.scalar_one_or_none()
    extra = (s.extra or {}) if s else {}
    if not extra.get("ai_enabled"):
        raise HTTPException(status_code=400, detail="AI 未启用，请在系统设置 → AI 配置中开启")

    from app.core.ai_utils import call_ai, resolve_ai_extra
    from app.core.services.ai_quota import consume_ai_quota
    from app.api.routers.products import _strip_html
    extra = await resolve_ai_extra(db, admin.tenant_id, extra)
    await consume_ai_quota(db, admin.tenant_id)
    content_text = _strip_html(body.content or "", max_chars=1000)
    system_prompt = (
        "You are a professional translator. Translate all provided Chinese content into natural English. "
        "Return ONLY a valid JSON object with keys: title_en, content_en, excerpt_en, seo_title_en, seo_description_en, seo_keywords_en. "
        "For content_en, preserve basic HTML structure. If a field is empty, return empty string."
    )
    user_prompt = (
        f"Translate this article from Chinese to English:\n"
        f"title: {(body.title or '')[:200]}\n"
        f"content: {content_text}\n"
        f"excerpt: {(body.excerpt or '')[:500]}\n"
        f"seo_title: {(body.seo_title or '')[:160]}\n"
        f"seo_description: {(body.seo_description or '')[:320]}\n"
        f"seo_keywords: {(body.seo_keywords or '')[:300]}\n\n"
        f"Return JSON only, no explanation."
    )

    raw = await call_ai(user_prompt, extra, system_prompt=system_prompt, max_tokens=2048, timeout=120)
    start = raw.find("{")
    if start == -1:
        raise HTTPException(status_code=502, detail="AI 返回格式异常，请重试")
    try:
        data, _ = _json.JSONDecoder().raw_decode(raw, start)
    except _json.JSONDecodeError:
        raise HTTPException(status_code=502, detail="AI 返回 JSON 解析失败，请重试")

    return ArticleTranslateResponse(
        title_en=data.get("title_en", ""),
        content_en=data.get("content_en", ""),
        excerpt_en=data.get("excerpt_en", ""),
        seo_title_en=data.get("seo_title_en", ""),
        seo_description_en=data.get("seo_description_en", ""),
        seo_keywords_en=data.get("seo_keywords_en", ""),
    )


@router.get("", response_model=dict)
async def list_articles(
    page:     int = Query(1, ge=1),
    per_page: int = Query(20, ge=1, le=100),
    status:   Optional[str] = None,
    keyword:  Optional[str] = None,
    db: AsyncSession = Depends(get_db),
    admin = Depends(get_admin_user),
):
    q = select(Article).where(Article.tenant_id == admin.tenant_id)
    if status:
        q = q.where(Article.status == status)
    if keyword:
        q = q.where(or_(
            Article.title.ilike(f"%{keyword}%"),
            Article.excerpt.ilike(f"%{keyword}%"),
        ))
    total = (await db.execute(select(func.count()).select_from(q.subquery()))).scalar()
    rows  = (await db.execute(q.order_by(Article.created_at.desc()).offset((page-1)*per_page).limit(per_page))).scalars().all()
    return {"total": total, "page": page, "per_page": per_page, "items": [ArticleOut.model_validate(r) for r in rows]}


@router.post("", response_model=ArticleOut, status_code=201)
async def create_article(
    body: ArticleCreate,
    db: AsyncSession = Depends(get_db),
    admin = Depends(get_admin_user),
):
    slug = body.slug or _slugify(body.title)
    # ensure slug uniqueness within tenant
    existing = (await db.execute(select(Article).where(Article.tenant_id == admin.tenant_id, Article.slug == slug))).scalar_one_or_none()
    if existing:
        slug = f"{slug}-{int(datetime.utcnow().timestamp())}"

    obj = Article(
        tenant_id       = admin.tenant_id,
        slug            = slug,
        **{k: v for k, v in body.model_dump(exclude={"slug"}).items()},
    )
    if obj.status == "published" and not obj.published_at:
        obj.published_at = datetime.utcnow()
    db.add(obj)
    await db.commit()
    await db.refresh(obj)
    return obj


@router.get("/{article_id}", response_model=ArticleOut)
async def get_article(
    article_id: int,
    db: AsyncSession = Depends(get_db),
    admin = Depends(get_admin_user),
):
    obj = (await db.execute(select(Article).where(Article.id == article_id, Article.tenant_id == admin.tenant_id))).scalar_one_or_none()
    if not obj:
        raise HTTPException(404, "Article not found")
    return obj


@router.put("/{article_id}", response_model=ArticleOut)
async def update_article(
    article_id: int,
    body: ArticleUpdate,
    db: AsyncSession = Depends(get_db),
    admin = Depends(get_admin_user),
):
    obj = (await db.execute(select(Article).where(Article.id == article_id, Article.tenant_id == admin.tenant_id))).scalar_one_or_none()
    if not obj:
        raise HTTPException(404, "Article not found")

    data = body.model_dump(exclude_unset=True)
    if "slug" in data and data["slug"]:
        # check slug collision (excluding self)
        dup = (await db.execute(
            select(Article).where(Article.tenant_id == admin.tenant_id, Article.slug == data["slug"], Article.id != article_id)
        )).scalar_one_or_none()
        if dup:
            raise HTTPException(400, "Slug already in use")
    elif "slug" not in data or not data.get("slug"):
        data.pop("slug", None)  # don't overwrite with empty

    for k, v in data.items():
        setattr(obj, k, v)

    if obj.status == "published" and not obj.published_at:
        obj.published_at = datetime.utcnow()

    await db.commit()
    await db.refresh(obj)
    return obj


@router.post("/{article_id}/preview-token", response_model=PreviewTokenResponse, summary="生成草稿预览 Token")
async def get_preview_token(
    article_id: int,
    db: AsyncSession = Depends(get_db),
    admin = Depends(get_admin_user),
):
    obj = (await db.execute(
        select(Article).where(Article.id == article_id, Article.tenant_id == admin.tenant_id)
    )).scalar_one_or_none()
    if not obj:
        raise HTTPException(404, "Article not found")
    # Token is idempotent: reuses existing token to keep preview URLs stable
    if not obj.preview_token:
        obj.preview_token = secrets.token_urlsafe(32)
        await db.commit()
        await db.refresh(obj)
    return {"token": obj.preview_token}


@router.delete("/{article_id}", status_code=204)
async def delete_article(
    article_id: int,
    db: AsyncSession = Depends(get_db),
    admin = Depends(get_admin_user),
):
    obj = (await db.execute(select(Article).where(Article.id == article_id, Article.tenant_id == admin.tenant_id))).scalar_one_or_none()
    if not obj:
        raise HTTPException(404, "Article not found")
    await db.delete(obj)
    await db.commit()
