from fastapi import APIRouter, HTTPException, Response, Header, Depends
from pydantic import BaseModel
import jwt
import datetime
import logging
from typing import List, Optional
from dbmodel import User, UserToken
import bcrypt
from ..dependencies import get_db

logger = logging.getLogger("sampacs")
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)

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

class LoginRequest(BaseModel):
    login: str
    password: str

class UserInfo(BaseModel):
    id: int
    login: str
    last_name: str
    first_name: str
    patr_name: str
    is_admin: bool

    class Config:
        exclude_none = True

class LoginSuccess(BaseModel):
    success: bool
    token: str
    user: UserInfo

    class Config:
        exclude_none = True

# Секретный ключ для JWT (в продакшене должен быть в конфигурации)
JWT_SECRET = "your-secret-key-here"
JWT_ALGORITHM = "HS256"

@router.post("/login", summary="Аутентификация пользователя", response_description="Результат аутентификации", responses={
    200: {
        "description": "Успешная аутентификация",
        "content": {
            "application/json": {
                "examples": {
                    "login_success": {
                        "summary": "Успешная аутентификация",
                        "value": {
                            "success": True,
                            "token": "jwt_token_here",
                            "user": {
                                "id": 1,
                                "login": "doctor",
                                "last_name": "Иванов",
                                "first_name": "Иван",
                                "patr_name": "Иванович",
                                "is_admin": False
                            }
                        }
                    }
                }
            }
        }
    },
    400: {"description": "Не указаны логин или пароль"},
    401: {"description": "Неверный логин или пароль"}
})
async def login(login_data: LoginRequest, response: Response, db: None = Depends(get_db)) -> LoginSuccess:
    """
    Аутентификация пользователя по логину и паролю.

    Пароль проверяется с помощью bcrypt.

    ## Возвращает:
    - `success`: true
    - `token`: JWT токен для последующих запросов (вечный, хранится в базе)
    - `user`: информация о пользователе

    ## Ошибки:
    - 400: Не указаны логин или пароль
    - 401: Неверный логин или пароль
    """
    if not login_data.login or not login_data.password:
        raise HTTPException(status_code=400, detail="Логин и пароль обязательны")

    try:
        logger.info(f"Login attempt for user: {login_data.login}")

        # Ищем пользователя
        user = User.get_or_none(User.login == login_data.login)

        if not user:
            logger.warning(f"User not found: {login_data.login}")
            raise HTTPException(status_code=401, detail="Неверный логин или пароль")

        # Проверяем пароль с помощью bcrypt
        if not bcrypt.checkpw(login_data.password.encode('utf-8'), user.passwd.encode('utf-8')):
            logger.warning(f"Invalid password for user: {login_data.login}")
            raise HTTPException(status_code=401, detail="Неверный логин или пароль")

        # Создаем JWT токен
        payload = {
            'user_id': user.id,
            'login': user.login,
            'last_name': user.last_name,
            'first_name': user.first_name,
            'patr_name': user.patr_name,
            'is_admin': user.is_admin,
            'exp': datetime.datetime.utcnow() + datetime.timedelta(days=365 * 10)  # 10 лет (вечный)
        }

        token = jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGORITHM)

        # Сохраняем токен в базе
        user_token = UserToken(
            user=user,
            token=token
        )
        user_token.save()

        # Создаем информацию о пользователе
        user_info = UserInfo(
            id=user.id,
            login=user.login,
            last_name=user.last_name,
            first_name=user.first_name,
            patr_name=user.patr_name,
            is_admin=user.is_admin
        )

        # Устанавливаем токен в куки
        response.set_cookie(
            key="auth_token",
            value=token,
            httponly=True,
            max_age=365 * 10 * 24 * 60 * 60,  # 10 лет
            secure=False,  # В продакшене должно быть True для HTTPS
            samesite="lax"
        )

        logger.info(f"Successful login for user: {login_data.login}, user_id: {user.id}, is_admin: {user.is_admin}")
        return LoginSuccess(
            success=True,
            token=token,
            user=user_info
        )
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error during login for user {login_data.login}: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail=f"Error during login for user {login_data.login}: {str(e)}")


@router.post("/logout", summary="Выход пользователя")
async def logout(response: Response, token: Optional[str] = None, authorization: Optional[str] = Header(None), db: None = Depends(get_db)):
    """
    Выход пользователя из системы.
    Удаляет токен из базы данных и очищает куки.

    ## Параметры:
    - `token`: JWT токен (можно передать в заголовке Authorization или в куках)

    ## Возвращает:
    - `success`: true
    """
    try:
        # Получаем токен из параметра, заголовка Authorization или кук
        if not token:
            # Проверяем заголовок Authorization: Bearer <token>
            if authorization and authorization.startswith("Bearer "):
                token = authorization[7:]  # Убираем "Bearer "

        # Если токен не найден, просто очищаем куки

        if token:
            # Удаляем токен из базы
            UserToken.delete().where(UserToken.token == token).execute()

            # Очищаем куки (даже если токен не найден)
            response.delete_cookie(key="auth_token")

        return {"success": True}
    except Exception as e:
        logger.error(f"Error during logout: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail="Internal server error")





@router.post("/validate", summary="Валидация токена")
async def validate_token(token: str, db: None = Depends(get_db)):
    """
    Валидация JWT токена.

    ## Параметры:
    - `token`: JWT токен для валидации

    ## Возвращает:
    - `valid`: true/false
    - `user_id`: ID пользователя если токен валиден
    - `is_admin`: флаг администратора если токен валиден

    ## Ошибки:
    - 400: Не указан токен
    """
    if not token:
        raise HTTPException(status_code=400, detail="Token is required")

    try:
        # Проверяем токен в базе
        user_token = UserToken.get_or_none(UserToken.token == token)
        if not user_token:
            return {"valid": False}

        # Декодируем JWT
        try:
            payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
        except (jwt.ExpiredSignatureError, jwt.InvalidTokenError):
            # Удаляем невалидный токен
            UserToken.delete().where(UserToken.token == token).execute()
            return {"valid": False}

        return {
            "valid": True,
            "user_id": user_token.user.id,
            "is_admin": user_token.user.is_admin
        }
    except Exception as e:
        logger.error(f"Error validating token: {str(e)}", exc_info=True)
        return {"valid": False}
