from datetime import datetime, timedelta, timezone

import bcrypt
from jose import JWTError, jwt
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.config import get_settings
from app.models import Account
from app.schemas import UserProfile

settings = get_settings()

# ─── 密码哈希 ──────────────────────────────────────────────


def hash_password(password: str) -> str:
    return bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt()).decode("utf-8")


def verify_password(plain: str, hashed: str) -> bool:
    return bcrypt.checkpw(plain.encode("utf-8"), hashed.encode("utf-8"))


# ─── JWT ───────────────────────────────────────────────────

def create_access_token(user_id: str, username: str) -> str:
    """生成 JWT token"""
    now = datetime.now(timezone.utc)
    payload = {
        "sub": user_id,
        "username": username,
        "iat": now,
        "exp": now + timedelta(minutes=settings.JWT_EXPIRE_MINUTES),
    }
    return jwt.encode(payload, settings.JWT_SECRET, algorithm=settings.JWT_ALGORITHM)


def decode_access_token(token: str) -> dict | None:
    """解码并验证 JWT token，失败返回 None"""
    try:
        return jwt.decode(token, settings.JWT_SECRET, algorithms=[settings.JWT_ALGORITHM])
    except JWTError:
        return None


# ─── 数据库操作 ─────────────────────────────────────────────

async def get_account_by_username(db: AsyncSession, username: str) -> Account | None:
    result = await db.execute(select(Account).where(Account.username == username))
    return result.scalar_one_or_none()


async def get_account_by_id(db: AsyncSession, user_id: str) -> Account | None:
    result = await db.execute(select(Account).where(Account.id == user_id))
    return result.scalar_one_or_none()


async def create_account(db: AsyncSession, username: str, password: str, nickname: str) -> Account:
    account = Account(
        username=username,
        password_hash=hash_password(password),
        nickname=nickname,
    )
    db.add(account)
    await db.flush()
    await db.refresh(account)
    return account
