"""
頻道 API(階段 3a)。

  - GET    /api/channels                 ─ 列出我能看到的頻道
  - POST   /api/channels                 ─ 建立新頻道(自動把建立者加為成員)
  - GET    /api/channels/{id}            ─ 取得頻道詳情
  - PATCH  /api/channels/{id}            ─ 更新頻道(只有建立者或 owner)
  - DELETE /api/channels/{id}            ─ 軟刪除(只有 owner)
  - POST   /api/channels/{id}/members    ─ 加成員(我邀請別人)
  - DELETE /api/channels/{id}/members/{user_id}  ─ 移除成員
"""

from collections import defaultdict
from datetime import datetime, timezone
from uuid import UUID

from fastapi import APIRouter, HTTPException, status
from sqlalchemy import select
from sqlalchemy.orm import selectinload

from app.core.deps import CurrentUser, DBSession
from app.core.ws_manager import manager as ws_manager
from app.models.channel import Channel, ChannelMember
from app.models.user import User
from app.schemas.channel import ChannelCreateRequest, ChannelPublic, ChannelUpdateRequest


router = APIRouter(prefix="/api/channels", tags=["channels"])


@router.get("", response_model=list[ChannelPublic], summary="列出我能看到的頻道")
async def list_channels(
    current_user: CurrentUser,
    db: DBSession,
) -> list[Channel]:
    """列出當前使用者參與的頻道,加上所有 public 頻道(就算還沒加入也看得到)。"""
    # 1. 抓我加入的頻道 ID
    member_stmt = select(ChannelMember.channel_id).where(
        ChannelMember.user_id == current_user.id,
    )
    my_channel_ids = set((await db.execute(member_stmt)).scalars().all())

    # 2. 抓所有 public 頻道 + 我已加入的所有頻道
    stmt = (
        select(Channel)
        .where(Channel.deleted_at.is_(None))
        .where(
            (Channel.channel_type == "public") | (Channel.id.in_(my_channel_ids))
        )
        .order_by(Channel.sort_order.asc(), Channel.created_at.asc())
    )
    return list((await db.execute(stmt)).scalars().all())


@router.post(
    "",
    response_model=ChannelPublic,
    status_code=status.HTTP_201_CREATED,
    summary="建立頻道",
)
async def create_channel(
    payload: ChannelCreateRequest,
    current_user: CurrentUser,
    db: DBSession,
) -> Channel:
    channel = Channel(
        name=payload.name,
        icon=payload.icon,
        description=payload.description,
        channel_type=payload.channel_type,
        created_by=current_user.id,
        is_default=False,
        sort_order=200,
    )
    db.add(channel)
    await db.flush()   # 拿到 channel.id

    # 建立者自動成為成員
    member = ChannelMember(channel_id=channel.id, user_id=current_user.id)
    db.add(member)

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


async def _get_channel_or_404(channel_id: UUID, db: DBSession) -> Channel:
    stmt = select(Channel).where(Channel.id == channel_id, Channel.deleted_at.is_(None))
    ch = (await db.execute(stmt)).scalar_one_or_none()
    if ch is None:
        raise HTTPException(status_code=404, detail="找不到此頻道")
    return ch


@router.get("/{channel_id}", response_model=ChannelPublic, summary="取得頻道詳情")
async def get_channel(channel_id: UUID, current_user: CurrentUser, db: DBSession) -> Channel:
    return await _get_channel_or_404(channel_id, db)


@router.patch("/{channel_id}", response_model=ChannelPublic, summary="更新頻道")
async def update_channel(
    channel_id: UUID,
    payload: ChannelUpdateRequest,
    current_user: CurrentUser,
    db: DBSession,
) -> Channel:
    ch = await _get_channel_or_404(channel_id, db)
    if current_user.role != "owner" and ch.created_by != current_user.id:
        raise HTTPException(status_code=403, detail="只有建立者或公司 owner 能修改頻道")

    if payload.name is not None:
        ch.name = payload.name
    if payload.icon is not None:
        ch.icon = payload.icon
    if payload.description is not None:
        ch.description = payload.description
    await db.commit()
    await db.refresh(ch)
    return ch


@router.delete("/{channel_id}", status_code=204, summary="軟刪除頻道(只有 owner)")
async def delete_channel(channel_id: UUID, current_user: CurrentUser, db: DBSession) -> None:
    ch = await _get_channel_or_404(channel_id, db)
    if ch.is_default:
        raise HTTPException(status_code=400, detail="預設頻道不能刪除")
    if current_user.role != "owner":
        raise HTTPException(status_code=403, detail="只有公司 owner 能刪頻道")
    ch.deleted_at = datetime.now(timezone.utc)
    await db.commit()


# ---------------------------------------------------------------------------
# 成員管理
# ---------------------------------------------------------------------------
@router.post("/{channel_id}/mark-read", status_code=204, summary="標記頻道已讀至此刻")
async def mark_channel_read(
    channel_id: UUID,
    current_user: CurrentUser,
    db: DBSession,
) -> None:
    """更新「我」在這個頻道的 last_read_at = 現在。

    LINE 風格的「已讀」就靠這個:其他人看自己訊息時,本端點會被觸發,
    伺服器記下「這個人讀到何時」,下次列訊息時就會在已讀名單裡看到他。

    冪等:如果還不是頻道成員,自動加入(只有 public 頻道允許自加)。
    """
    ch = await _get_channel_or_404(channel_id, db)

    member = (await db.execute(
        select(ChannelMember).where(
            ChannelMember.channel_id == channel_id,
            ChannelMember.user_id == current_user.id,
        )
    )).scalar_one_or_none()

    if member is None:
        # 自動加入(public 頻道)
        if ch.channel_type == "private":
            raise HTTPException(status_code=403, detail="這是私密頻道,需要邀請才能加入")
        member = ChannelMember(channel_id=channel_id, user_id=current_user.id)
        db.add(member)

    member.last_read_at = datetime.now(timezone.utc)
    await db.commit()
    # 廣播給「其他人」:有人讀到此刻(發訊者要更新「已讀」頭像)
    # exclude_user_id=自己 避免回音迴圈(自己收到自己的 read_receipt 又打 API 又廣播...)
    await ws_manager.broadcast(
        {
            "type": "read_receipt",
            "channel_id": str(channel_id),
            "user": {
                "id": str(current_user.id),
                "display_name": current_user.display_name,
                "avatar_url": current_user.avatar_url,
            },
            "last_read_at": member.last_read_at.isoformat(),
        },
        exclude_user_id=current_user.id,
    )


@router.post("/{channel_id}/join", status_code=204, summary="加入頻道(自己加自己)")
async def join_channel(channel_id: UUID, current_user: CurrentUser, db: DBSession) -> None:
    """讓使用者加入 public 頻道。private 頻道只能透過邀請(下方 add_member)。"""
    ch = await _get_channel_or_404(channel_id, db)
    if ch.channel_type == "private":
        raise HTTPException(status_code=403, detail="這是私密頻道,需要邀請才能加入")

    # 檢查是否已加入
    existing = await db.execute(
        select(ChannelMember).where(
            ChannelMember.channel_id == channel_id,
            ChannelMember.user_id == current_user.id,
        )
    )
    if existing.scalar_one_or_none() is not None:
        return  # 已是成員,什麼都不做

    db.add(ChannelMember(channel_id=channel_id, user_id=current_user.id))
    await db.commit()
