import jwt
from datetime import datetime, timedelta, timezone
from passlib.context import CryptContext
from pydantic import BaseModel
from pymongo import MongoClient
from bson import ObjectId
from src.config import mongo_settings, auth_settings

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
# pwd_context = CryptContext(schemes=["bcrypt"], bcrypt__ident="2b", deprecated="auto")
class UserCreate(BaseModel):
    username: str
    password: str

class Token(BaseModel):
    access_token: str
    token_type: str

class AuthService:
    def __init__(self):
        self.client = MongoClient(mongo_settings.uri)
        self.db = self.client[mongo_settings.db]
        self.collection = self.db[auth_settings.collection]
        self.collection.create_index("username", unique=True)

    def verify_password(self, plain_password, hashed_password):
        return pwd_context.verify(plain_password, hashed_password)

    def get_password_hash(self, password):
        return pwd_context.hash(password)

    def get_user_by_username(self, username: str):
        return self.collection.find_one({"username": username})

    def get_user_by_id(self, user_id: str):
        try:
            return self.collection.find_one({"_id": ObjectId(user_id)})
        except Exception:
            return None

    def create_user(self, user: UserCreate):
        hashed_password = self.get_password_hash(user.password)
        user_doc = {
            "username": user.username,
            "password_hash": hashed_password,
            "created_at": datetime.now(timezone.utc)
        }
        result = self.collection.insert_one(user_doc)
        return str(result.inserted_id)

    def create_access_token(self, subject: str, expires_delta: timedelta | None = None):
        to_encode = {"sub": subject}
        if expires_delta:
            expire = datetime.now(timezone.utc) + expires_delta
        else:
            expire = datetime.now(timezone.utc) + timedelta(minutes=auth_settings.access_token_expire_minutes)
        to_encode.update({"exp": expire})
        encoded_jwt = jwt.encode(to_encode, auth_settings.secret_key, algorithm=auth_settings.algorithm)
        return encoded_jwt
