from datetime import datetime, timedelta, timezone
from typing import Optional
import bcrypt
from fastapi import Depends, HTTPException, Request, status
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt

from app.config import settings

# --- НАСТРОЙКИ (В реальном проекте берите из .env через pydantic-settings) ---
SECRET_KEY = settings.SECRET_KEY
ALGORITHM = settings.ALGORITHM
ACCESS_TOKEN_EXPIRE_MINUTES = 60
COOKIE_NAME = "WorkTools_token"

# Схема для работы документации Swagger UI (/docs). auto_error=False обязателен!
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login", auto_error=False)


# ==========================================
# 1. РАБОТА С ПАРОЛЯМИ (БЕЗ PASSLIB)
# ==========================================
def get_password_hash(password: str) -> str:
    """Хеширование пароля для сохранения в БД."""
    pwd_bytes = password.encode('utf-8')
    salt = bcrypt.gensalt()
    return bcrypt.hashpw(pwd_bytes, salt).decode('utf-8')


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """Проверка соответствия введенного пароля хешу из БД."""
    return bcrypt.checkpw(
        plain_password.encode('utf-8'),
        hashed_password.encode('utf-8')
    )


# ==========================================
# 2. РАБОТА С JWT ТОКЕНАМИ
# ==========================================
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
    """Создание JWT access токена."""
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.now(timezone.utc) + expires_delta
    else:
        expire = datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)

    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


# ==========================================
# 3. ЗАВИСИМОСТИ ИЗВЛЕЧЕНИЯ И ВАЛИДАЦИИ
# ==========================================
async def get_token_from_cookie_or_header(
        request: Request,
        header_token: Optional[str] = Depends(oauth2_scheme)
) -> str:
    """Извлекает токен из Cookies (web) или Bearer Header (mobile)."""
    # 1. Ищем в куках
    cookie_token = request.cookies.get(COOKIE_NAME)
    if cookie_token:
        # Убираем префикс Bearer, если фронтенд передал его внутрь куки
        if cookie_token.startswith("Bearer "):
            return cookie_token.split(" ")[1]
        return cookie_token

    # 2. Ищем в заголовках (если кук нет)
    if header_token:
        return header_token

    # 3. Если токена нет нигде
    raise HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Токен авторизации отсутствует",
        headers={"WWW-Authenticate": "Bearer"},
    )


async def get_current_user(token: str = Depends(get_token_from_cookie_or_header)) -> str:
    """Декодирует токен и возвращает username (sub). Данную функцию импортируют в роуты."""
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Не удалось валидировать учетные данные",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception

    # Имитация запроса в вашу БД:
    # user = await db.users.find_one({"username": username})
    # if user is None: raise credentials_exception

    return username
