"""平台账号业务逻辑

账号与资产的关系：Asset.account 按名称引用账号（字符串，兼容历史自由文本）。
重命名账号时同步更新所有引用资产，保证两边一致。
"""

from typing import Dict, List

from fastapi import HTTPException, status
from sqlalchemy import func
from sqlmodel import Session, select

from app.models.asset import Account, Asset
from app.schemas.account import AccountCreate, AccountRead, AccountUpdate


def _asset_counts(session: Session) -> Dict[str, int]:
    """按 account 名称统计引用资产数"""
    rows = session.exec(
        select(Asset.account, func.count(Asset.id))
        .where(Asset.account.is_not(None))  # type: ignore[union-attr]
        .group_by(Asset.account)
    ).all()
    return {name: cnt for name, cnt in rows}


def _to_read(account: Account, counts: Dict[str, int]) -> AccountRead:
    read = AccountRead.model_validate(account)
    read.asset_count = counts.get(account.name, 0)
    return read


def list_accounts(session: Session) -> List[AccountRead]:
    counts = _asset_counts(session)
    accounts = session.exec(select(Account).order_by(Account.name.asc())).all()
    return [_to_read(a, counts) for a in accounts]


def _get_account(session: Session, account_id: int) -> Account:
    account = session.get(Account, account_id)
    if not account:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="账号不存在")
    return account


def _check_name_taken(session: Session, name: str, exclude_id: int | None = None) -> None:
    stmt = select(Account).where(Account.name == name)
    if exclude_id is not None:
        stmt = stmt.where(Account.id != exclude_id)
    if session.exec(stmt).first():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, detail=f"账号已存在：{name}"
        )


def create_account(session: Session, data: AccountCreate) -> AccountRead:
    name = data.name.strip()
    if not name:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="账号名称不能为空")
    _check_name_taken(session, name)
    account = Account(name=name, platform=data.platform, remark=data.remark)
    session.add(account)
    session.commit()
    session.refresh(account)
    return _to_read(account, _asset_counts(session))


def update_account(session: Session, account_id: int, data: AccountUpdate) -> AccountRead:
    account = _get_account(session, account_id)
    if data.name is not None:
        new_name = data.name.strip()
        if not new_name:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="账号名称不能为空")
        if new_name != account.name:
            _check_name_taken(session, new_name, exclude_id=account.id)
            # 同步更新引用该账号的资产，避免重命名后资产端失联
            assets = session.exec(select(Asset).where(Asset.account == account.name)).all()
            for a in assets:
                a.account = new_name
                session.add(a)
            account.name = new_name
    if data.platform is not None:
        account.platform = data.platform or None
    if data.remark is not None:
        account.remark = data.remark or None
    session.add(account)
    session.commit()
    session.refresh(account)
    return _to_read(account, _asset_counts(session))


def delete_account(session: Session, account_id: int) -> Dict[str, int]:
    account = _get_account(session, account_id)
    affected = len(session.exec(select(Asset.id).where(Asset.account == account.name)).all())
    session.delete(account)
    session.commit()
    # 资产端保留原账号名文本（不级联清空），由用户自行处理
    return {"affected_assets": affected}
