"""认证路由：登录 / 获取当前用户"""
import json
import time
from collections import defaultdict
from datetime import datetime, timedelta
from fastapi import APIRouter, Depends, HTTPException, Request
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
import jwt
import bcrypt

from app.api.deps import get_db, get_current_user
from app.config import settings
from app.core.models.user import User
from app.core.models.tenant import Tenant
from app.schemas.auth import LoginRequest, TokenResponse, UserInfo

router = APIRouter(prefix="/auth", tags=["认证"])

# 简单内存速率限制：每个 IP 5分钟内最多 10 次失败
_fail_log: dict[str, list[float]] = defaultdict(list)
_WINDOW = 300   # 5 分钟
_MAX_FAILS = 10


def _check_rate_limit(ip: str) -> None:
    now = time.time()
    attempts = [t for t in _fail_log[ip] if now - t < _WINDOW]
    _fail_log[ip] = attempts
    if len(attempts) >= _MAX_FAILS:
        raise HTTPException(status_code=429, detail="登录尝试过于频繁，请 5 分钟后重试")


def _record_fail(ip: str) -> None:
    _fail_log[ip].append(time.time())


def _make_token(user_id: int, is_superadmin: bool = False) -> str:
    payload = {
        "sub": str(user_id),
        "exp": datetime.utcnow() + timedelta(days=7),
        "sa": 1 if is_superadmin else 0,
    }
    return jwt.encode(payload, settings.SECRET_KEY, algorithm="HS256")


def _verify_password(plain: str, hashed: str) -> bool:
    try:
        return bcrypt.checkpw(plain.encode(), hashed.encode())
    except Exception:
        return False


@router.post("/login", response_model=TokenResponse, summary="管理员登录")
async def login(request: Request, body: LoginRequest, db: AsyncSession = Depends(get_db)):
    ip = request.client.host if request.client else "unknown"
    _check_rate_limit(ip)

    if body.store_domain:
        # 指定了店铺域名：精确定位该租户下的用户，防止同邮箱跨租户冲突
        result = await db.execute(
            select(User)
            .join(Tenant, User.tenant_id == Tenant.id)
            .where(
                User.email == body.email,
                User.is_active == True,
                Tenant.domain == body.store_domain,
                Tenant.status == "active",
            )
        )
        user: User | None = result.scalar_one_or_none()
    else:
        # 未指定店铺域名：兼容单租户场景
        # - 全局唯一邮箱 → 直接登录（向后兼容）
        # - 多租户同邮箱 → 要求填写店铺域名
        all_result = await db.execute(
            select(User).where(User.email == body.email, User.is_active == True)
        )
        users = all_result.scalars().all()
        if len(users) > 1:
            _record_fail(ip)
            raise HTTPException(
                status_code=400,
                detail="该邮箱在多个店铺中存在，请在「店铺域名」字段填写您的店铺域名后重试",
            )
        user = users[0] if users else None

    if not user or not _verify_password(body.password, user.password_hash):
        _record_fail(ip)
        raise HTTPException(status_code=401, detail="邮箱或密码错误")

    token = _make_token(user.id, bool(user.is_superadmin))
    return TokenResponse(
        token=token,
        user=UserInfo(
            id=user.id,
            email=user.email,
            name=(
                (lambda p: p.get("Name") or p.get("name"))(
                    json.loads(user.profile) if isinstance(user.profile, str) else (user.profile or {})
                ) or user.email.split("@")[0]
            ),
            role=user.role,
            is_superadmin=bool(user.is_superadmin),
        ),
    )


@router.get("/me", response_model=UserInfo, summary="获取当前登录用户")
async def me(current_user: User = Depends(get_current_user)):
    return UserInfo(
        id=current_user.id,
        email=current_user.email,
        name=(
            (lambda p: p.get("Name") or p.get("name"))(
                json.loads(current_user.profile) if isinstance(current_user.profile, str) else (current_user.profile or {})
            ) or current_user.email.split("@")[0]
        ),
        role=current_user.role,
        is_superadmin=bool(current_user.is_superadmin),
    )
