from fastapi import APIRouter, Depends, HTTPException, Query, Request
from sqlalchemy.orm import Session, joinedload
from sqlalchemy import func
from typing import List, Optional, Dict, Any
from datetime import datetime, date
from pathlib import Path

from ..database import get_db
from ..models import Topic, TopicField, TopicConfigField, Article, PublishRecord, ContentMetrics
from ..schemas import (
    TopicCreate, TopicUpdate, TopicResponse, TopicScoreRequest,
    PublishRequest, PublishActionRequest, PublishRecordResponse
)
from .auth import get_current_user

router = APIRouter(prefix="/api/topics", tags=["topics"], dependencies=[Depends(get_current_user)])

PROJECT_ROOT = Path(__file__).parent.parent.parent


@router.get("", response_model=List[TopicResponse])
def list_topics(
    field_id: Optional[int] = None,
    status: Optional[str] = None,
    tag: Optional[str] = None,
    search: Optional[str] = None,
    sort_by: str = Query("priority_score", enum=["priority_score", "created_at", "title", "updated_at"]),
    order: str = Query("desc", enum=["asc", "desc"]),
    limit: int = Query(50, le=200),
    offset: int = Query(0, ge=0),
    db: Session = Depends(get_db)
):
    db.expire_all()
    query = db.query(Topic).options(joinedload(Topic.field))

    if field_id:
        query = query.filter(Topic.field_id == field_id)
    if status:
        query = query.filter(Topic.status == status)
    if tag:
        query = query.filter(Topic.tags.contains([tag]))
    if search:
        query = query.filter(Topic.title.contains(search))

    sort_col = getattr(Topic, sort_by, Topic.priority_score)
    if order == "desc":
        query = query.order_by(sort_col.desc())
    else:
        query = query.order_by(sort_col.asc())

    return query.offset(offset).limit(limit).all()


@router.get("/stats")
def topic_stats(
    db: Session = Depends(get_db),
    current_user=Depends(get_current_user)
):
    total = db.query(Topic).count()
    raw = db.query(Topic.status, func.count()).group_by(Topic.status).all()
    by_status = {s: c for s, c in raw}

    today = date.today()
    today_count = db.query(Topic).filter(func.date(Topic.created_at) == today).count()

    published = db.query(Topic).filter(Topic.status == "published").count()
    metrics_count = db.query(ContentMetrics).count()

    return {
        "total": total,
        "by_status": by_status,
        "published": published,
        "today_created": today_count,
        "metrics_count": metrics_count
    }


@router.post("", response_model=TopicResponse)
def create_topic(
    data: TopicCreate,
    db: Session = Depends(get_db),
    current_user=Depends(get_current_user)
):
    topic_id = data.id
    if not topic_id:
        max_topic = db.query(Topic).order_by(Topic.id.desc()).first()
        if max_topic and max_topic.id.startswith("T"):
            try:
                num = int(max_topic.id[1:]) + 1
                topic_id = f"T{num:03d}"
            except:
                topic_id = f"T{datetime.now().strftime('%m%d%H%M')}"
        else:
            topic_id = f"T{datetime.now().strftime('%m%d%H%M')}"

    field_name = None
    if data.field_id:
        field = db.query(TopicField).filter(TopicField.id == data.field_id).first()
        if field:
            field_name = field.name

    topic = Topic(
        id=topic_id,
        field_id=data.field_id,
        field_name=field_name,
        title=data.title,
        format=data.format,
        core_concept=data.core_concept,
        audience_pain=data.audience_pain,
        unique_angle=data.unique_angle,
        priority=data.priority,
        status="pending",
        tags=data.tags or [],
        custom_data=data.custom_data or {},
        scoring_data=data.scoring_data or {},
    )
    db.add(topic)
    db.commit()
    db.refresh(topic)
    return topic


@router.get("/{topic_id}", response_model=TopicResponse)
def get_topic(topic_id: str, db: Session = Depends(get_db)):
    topic = db.query(Topic).options(joinedload(Topic.field)).filter(Topic.id == topic_id).first()
    if not topic:
        raise HTTPException(status_code=404, detail="Topic not found")
    return topic


@router.put("/{topic_id}", response_model=TopicResponse)
def update_topic(
    topic_id: str,
    data: TopicUpdate,
    db: Session = Depends(get_db),
    current_user=Depends(get_current_user)
):
    topic = db.query(Topic).filter(Topic.id == topic_id).first()
    if not topic:
        raise HTTPException(status_code=404, detail="Topic not found")

    if data.field_id is not None:
        topic.field_id = data.field_id
        if data.field_id:
            field = db.query(TopicField).filter(TopicField.id == data.field_id).first()
            topic.field_name = field.name if field else None

    for k, v in data.model_dump(exclude_unset=True, exclude={"field_id"}).items():
        if k == "tags" or k == "custom_data" or k == "scoring_data":
            if v is not None:
                setattr(topic, k, v)
        elif v is not None:
            setattr(topic, k, v)

    topic.updated_at = datetime.now()
    db.commit()
    db.refresh(topic)
    return topic


@router.delete("/{topic_id}")
def delete_topic(
    topic_id: str,
    db: Session = Depends(get_db),
    current_user=Depends(get_current_user)
):
    topic = db.query(Topic).filter(Topic.id == topic_id).first()
    if not topic:
        raise HTTPException(status_code=404, detail="Topic not found")
    db.delete(topic)
    db.commit()
    return {"ok": True}


@router.post("/{topic_id}/score")
def score_topic(
    topic_id: str,
    data: TopicScoreRequest,
    db: Session = Depends(get_db),
    current_user=Depends(get_current_user)
):
    topic = db.query(Topic).filter(Topic.id == topic_id).first()
    if not topic:
        raise HTTPException(status_code=404, detail="Topic not found")

    topic.scoring_data = data.scoring_data

    if data.scoring_data and topic.field_id:
        configs = db.query(TopicConfigField).filter(
            TopicConfigField.field_id == topic.field_id
        ).all()

        total_weight = 0
        weighted_sum = 0
        for cfg in configs:
            val = data.scoring_data.get(cfg.key)
            if val is not None and cfg.field_type == "number":
                if cfg.min_value is not None:
                    val = max(val, cfg.min_value)
                if cfg.max_value is not None:
                    val = min(val, cfg.max_value)
                normalized = (val - cfg.min_value) / (cfg.max_value - cfg.min_value) if cfg.max_value != cfg.min_value else 0.5
                weighted_sum += normalized * cfg.weight
                total_weight += cfg.weight

        if total_weight > 0:
            topic.total_score = round(weighted_sum / total_weight * 100, 1)
            topic.priority_score = int(topic.total_score)

    topic.updated_at = datetime.now()
    db.commit()
    db.refresh(topic)
    return {"priority_score": topic.priority_score, "total_score": topic.total_score}


@router.post("/{topic_id}/publish")
def publish_topic(topic_id: str, req: PublishRequest, db: Session = Depends(get_db)):
    topic = db.query(Topic).filter(Topic.id == topic_id).first()
    if not topic:
        raise HTTPException(status_code=404, detail="Topic not found")
    if topic.status not in ("pending", "ready", "draft"):
        raise HTTPException(status_code=400, detail=f"选题状态({topic.status})不允许发布")

    topic.status = "published"
    topic.published_at = date.today()
    topic.updated_at = datetime.now()
    topic.platform_urls = req.platform_urls

    record = PublishRecord(
        topic_id=topic_id,
        platform="all",
        action="publish",
        status="success",
        description=f"选题 {topic_id} 已发布"
    )
    db.add(record)
    db.commit()
    return {"ok": True, "topic_id": topic_id}


@router.get("/{topic_id}/articles", response_model=List[Dict[str, Any]])
def get_topic_articles(topic_id: str, db: Session = Depends(get_db)):
    topic = db.query(Topic).filter(Topic.id == topic_id).first()
    if not topic:
        raise HTTPException(status_code=404, detail="Topic not found")
    articles = db.query(Article).filter(Article.topic_id == topic_id).all()
    return [a.to_dict() if hasattr(a, 'to_dict') else {
        "id": a.id, "topic_id": a.topic_id, "platform": a.platform,
        "status": a.status, "file_path": a.file_path
    } for a in articles]


@router.get("/{topic_id}/metrics", response_model=List[Dict[str, Any]])
def get_topic_metrics(topic_id: str, db: Session = Depends(get_db)):
    metrics = db.query(ContentMetrics).filter(ContentMetrics.topic_id == topic_id).all()
    return [m.to_dict() for m in metrics]


@router.post("/{topic_id}/lock")
def lock_topic(topic_id: str, db: Session = Depends(get_db), current_user=Depends(get_current_user)):
    topic = db.query(Topic).filter(Topic.id == topic_id).first()
    if not topic:
        raise HTTPException(status_code=404, detail="Topic not found")
    topic.lock_by = current_user.username
    topic.lock_at = datetime.now()
    db.commit()
    return {"ok": True}


@router.post("/{topic_id}/unlock")
def unlock_topic(topic_id: str, db: Session = Depends(get_db), current_user=Depends(get_current_user)):
    topic = db.query(Topic).filter(Topic.id == topic_id).first()
    if not topic:
        raise HTTPException(status_code=404, detail="Topic not found")
    topic.lock_by = None
    topic.lock_at = None
    db.commit()
    return {"ok": True}


@router.post("/batch-update-status")
def batch_update_status(
    topic_ids: List[str],
    status: str,
    db: Session = Depends(get_db),
    current_user=Depends(get_current_user)
):
    updated = db.query(Topic).filter(Topic.id.in_(topic_ids)).update(
        {Topic.status: status, Topic.updated_at: datetime.now()},
        synchronize_session=False
    )
    db.commit()
    return {"ok": True, "updated": updated}


@router.get("/field-distribution")
def field_distribution(
    db: Session = Depends(get_db),
    current_user=Depends(get_current_user)
):
    rows = db.query(
        Topic.field_name,
        func.count(Topic.id).label("count")
    ).group_by(Topic.field_name).all()
    return [{"field": r.field_name or "未分类", "count": r.count} for r in rows]