from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile, status
from sqlalchemy import func
from sqlalchemy.orm import Session, joinedload

from app.database import SessionLocal, get_db, release_db_connection
from app.dependencies import require_admin_token
from app.models import User
from app.schemas import (
    CommunityPostCommentIdRequest,
    CommunityPostIdRequest,
    CommunityPostListResponse,
    CommunityPostOut,
    Message,
)
from app.models_admin import CommunityPost, CommunityPostComment, CommunityPostLike, CommunityPostShare
from app.services.admin_service import (
    create_community_post,
    delete_community_comment,
    delete_community_post as remove_community_post,
    list_community_posts as fetch_community_posts,
    save_community_media,
    serialize_community_comment,
    serialize_community_post,
    update_community_post,
)

router = APIRouter(tags=["admin-community"])


def _posts_with_engagement(db: Session, posts: list[CommunityPost]) -> list[dict]:
    if not posts:
        return []

    post_ids = [post.id for post in posts]
    likes_by_post = dict(
        db.query(CommunityPostLike.post_id, func.count(CommunityPostLike.id))
        .filter(CommunityPostLike.post_id.in_(post_ids))
        .group_by(CommunityPostLike.post_id)
        .all()
    )
    comments_by_post = dict(
        db.query(CommunityPostComment.post_id, func.count(CommunityPostComment.id))
        .filter(CommunityPostComment.post_id.in_(post_ids))
        .group_by(CommunityPostComment.post_id)
        .all()
    )
    shares_by_post = dict(
        db.query(CommunityPostShare.post_id, func.count(CommunityPostShare.id))
        .filter(CommunityPostShare.post_id.in_(post_ids))
        .group_by(CommunityPostShare.post_id)
        .all()
    )

    share_counts: dict[int, dict[str, int]] = {post_id: {} for post_id in post_ids}
    for post_id, platform, count in (
        db.query(
            CommunityPostShare.post_id,
            CommunityPostShare.platform,
            func.count(CommunityPostShare.id),
        )
        .filter(CommunityPostShare.post_id.in_(post_ids))
        .group_by(CommunityPostShare.post_id, CommunityPostShare.platform)
        .all()
    ):
        share_counts.setdefault(post_id, {})[str(platform)] = int(count)

    comments_by_post_id: dict[int, list[CommunityPostComment]] = {post_id: [] for post_id in post_ids}
    all_comments = (
        db.query(CommunityPostComment)
        .options(joinedload(CommunityPostComment.user))
        .filter(CommunityPostComment.post_id.in_(post_ids))
        .order_by(
            CommunityPostComment.post_id.asc(),
            CommunityPostComment.created_at.asc(),
            CommunityPostComment.id.asc(),
        )
        .all()
    )
    for comment in all_comments:
        comments_by_post_id.setdefault(comment.post_id, []).append(comment)

    serialized: list[dict] = []
    for post in posts:
        data = serialize_community_post(post)
        data["likes_count"] = int(likes_by_post.get(post.id, 0))
        data["comments_count"] = int(comments_by_post.get(post.id, 0))
        data["shares_count"] = int(shares_by_post.get(post.id, 0))
        data["share_counts"] = share_counts.get(post.id, {})
        data["comments"] = [
            serialize_community_comment(comment)
            for comment in comments_by_post_id.get(post.id, [])
        ]
        serialized.append(data)
    return serialized


@router.post(
    "/add-community-post",
    response_model=CommunityPostOut,
    status_code=status.HTTP_201_CREATED,
    summary="Create a community post (multipart: title, media, type, content)",
)
async def add_community_post(
    db: Session = Depends(get_db),
    admin: User = Depends(require_admin_token),
    title: str = Form(..., description="Post title, e.g. Hurray!"),
    post_type: str = Form(..., description="Post type/category from the Type dropdown"),
    content: str = Form(..., description="Post body text"),
    media: UploadFile | None = File(default=None, description="Optional image or video"),
):
    title_clean = title.strip()
    post_type_clean = post_type.strip()
    content_clean = content.strip()
    if not title_clean:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Title is required")
    if not post_type_clean:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Type is required")
    if not content_clean:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Content is required")

    admin_id = admin.id
    release_db_connection(db)
    media_path: str | None = None
    media_content_type: str | None = None
    if media and media.filename:
        media_path, media_content_type = await save_community_media(media)

    write_db = SessionLocal()
    try:
        admin_user = write_db.get(User, admin_id)
        if admin_user is None:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Admin not found")
        post = create_community_post(
            db=write_db,
            admin=admin_user,
            title=title_clean,
            post_type=post_type_clean,
            content=content_clean,
            media_path=media_path,
            media_content_type=media_content_type,
        )
        return serialize_community_post(post)
    finally:
        write_db.close()


@router.post(
    "/edit-community-post",
    response_model=CommunityPostOut,
    summary="Update a community post (multipart: post_id, title, media, type, content)",
)
async def edit_community_post(
    db: Session = Depends(get_db),
    _: User = Depends(require_admin_token),
    post_id: int = Form(..., ge=1, description="Community post id to update"),
    title: str = Form(..., description="Post title"),
    post_type: str = Form(..., description="Post type/category from the Type dropdown"),
    content: str = Form(..., description="Post body text"),
    media: UploadFile | None = File(default=None, description="Optional new image or video"),
    remove_media: bool = Form(default=False, description="Set true to remove existing media without uploading a new file"),
):
    title_clean = title.strip()
    post_type_clean = post_type.strip()
    content_clean = content.strip()
    if not title_clean:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Title is required")
    if not post_type_clean:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Type is required")
    if not content_clean:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Content is required")

    exists = db.query(CommunityPost.id).filter(CommunityPost.id == post_id).first()
    if not exists:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Community post not found")

    replace_media = False
    media_path: str | None = None
    media_content_type: str | None = None
    release_db_connection(db)
    if media and media.filename:
        media_path, media_content_type = await save_community_media(media)
        replace_media = True

    write_db = SessionLocal()
    try:
        post = (
            write_db.query(CommunityPost)
            .options(joinedload(CommunityPost.created_by))
            .filter(CommunityPost.id == post_id)
            .first()
        )
        if not post:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Community post not found")
        post = update_community_post(
            db=write_db,
            post=post,
            title=title_clean,
            post_type=post_type_clean,
            content=content_clean,
            media_path=media_path,
            media_content_type=media_content_type,
            replace_media=replace_media,
            clear_media=remove_media and not replace_media,
        )
        return serialize_community_post(post)
    finally:
        write_db.close()


@router.get(
    "/list-community-posts",
    response_model=CommunityPostListResponse,
    summary="List all community posts with full card data (newest first)",
)
def list_community_posts(
    db: Session = Depends(get_db),
    _: User = Depends(require_admin_token),
):
    posts = fetch_community_posts(db)
    serialized = _posts_with_engagement(db, posts)
    return CommunityPostListResponse(total=len(serialized), posts=serialized)


@router.post(
    "/delete-community-post",
    response_model=Message,
    summary="Delete a community post by id",
)
def delete_community_post(
    body: CommunityPostIdRequest,
    db: Session = Depends(get_db),
    _: User = Depends(require_admin_token),
):
    if not remove_community_post(db, body.post_id):
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Community post not found")
    return Message(message="Community post deleted")


@router.post(
    "/delete-community-comment",
    response_model=Message,
    summary="Delete one community comment by id",
)
def delete_comment(
    body: CommunityPostCommentIdRequest,
    db: Session = Depends(get_db),
    _: User = Depends(require_admin_token),
):
    if not delete_community_comment(db, body.comment_id):
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Comment not found")
    return Message(message="Comment deleted")
