from sqlalchemy.orm import Session
from fastapi import HTTPException, status
from typing import Optional, List
import bcrypt
from jose import jwt
from datetime import datetime, timedelta
import os
from . import repository
from .schema import UserCreate, UserUpdate, UserLogin, UserLoginResponse, UserResponse


SECRET_KEY = os.environ.get("SECRET_KEY", "your-secret-key-change-in-production")
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30


def _hash_password(password: str) -> str:
    salt = bcrypt.gensalt()
    return bcrypt.hashpw(password.encode("utf-8"), 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"))


def _create_access_token(data: dict) -> str:
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


def register_user(db: Session, data: UserCreate) -> UserResponse:
    existing_user = repository.get_by_email(db, data.email)
    if existing_user:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="User with this email already exists"
        )
    
    password_hash = _hash_password(data.password)
    
    user_data = data.model_dump(exclude={"password"})
    user_data["password_hash"] = password_hash
    user_data["is_active"] = True
    
    user = repository.create(db, user_data)
    db.commit()
    db.refresh(user)
    
    return user


def login_user(db: Session, data: UserLogin) -> UserLoginResponse:
    user = repository.get_by_email(db, data.email)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid email or password"
        )
    
    if not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Account is inactive"
        )
    
    if not _verify_password(data.password, user.password_hash):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid email or password"
        )
    
    access_token = _create_access_token({"sub": user.id, "email": user.email, "role": user.role})
    
    return UserLoginResponse(
        access_token=access_token,
        token_type="bearer",
        user=user
    )


def get_user_profile(db: Session, user_id: str) -> UserResponse:
    user = repository.get_by_id(db, user_id)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    
    return user


def update_user_profile(db: Session, user_id: str, data: UserUpdate) -> UserResponse:
    user = repository.get_by_id(db, user_id)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    
    update_data = data.model_dump(exclude_unset=True)
    
    if "email" in update_data and update_data["email"] != user.email:
        existing_user = repository.get_by_email(db, update_data["email"])
        if existing_user:
            raise HTTPException(
                status_code=status.HTTP_409_CONFLICT,
                detail="User with this email already exists"
            )
    
    if "password" in update_data:
        update_data["password_hash"] = _hash_password(update_data.pop("password"))
    
    updated_user = repository.update(db, user_id, update_data)
    db.commit()
    db.refresh(updated_user)
    
    return updated_user


def list_users(db: Session, limit: int, offset: int, role: Optional[str], is_active: Optional[bool]) -> List[UserResponse]:
    users = repository.list_all(db, limit, offset, role, is_active)
    return users


def get_user_by_id(db: Session, user_id: str) -> UserResponse:
    user = repository.get_by_id(db, user_id)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    
    return user


def delete_user(db: Session, user_id: str) -> dict:
    success = repository.delete(db, user_id)
    if not success:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    
    db.commit()
    return {"message": "User deleted successfully"}