# bedrock_server_manager/web/routers/register.py
"""
FastAPI router for user registration management.

This module provides endpoints for:
- Generating registration tokens (Admin only).
- Serving the registration page.
- Handling user registration submissions.
"""

import logging
import secrets
import time

from fastapi import APIRouter, Depends, HTTPException, Request, status
from fastapi.responses import JSONResponse
from sqlalchemy.exc import IntegrityError

from ...context import AppContext
from ...db.models import RegistrationToken, User
from ..auth_utils import get_admin_user, get_password_hash
from ..dependencies import get_app_context
from ..schemas import ActionResponse, GenerateTokenPayload, UserLoginPayload
from ..schemas import UserResponse as UserSchema

logger = logging.getLogger(__name__)

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


@router.post("/generate-token", response_model=ActionResponse, include_in_schema=False)
async def generate_token(
    request: Request,
    data: GenerateTokenPayload,
    current_user: UserSchema = Depends(get_admin_user),
    app_context: AppContext = Depends(get_app_context),
):
    """
    Generates a new registration token.
    """

    token = secrets.token_urlsafe(32)
    expires = int(time.time()) + 86400  # 24 hours
    registration_token = RegistrationToken(token=token, role=data.role, expires=expires)
    with app_context.db.session_manager() as db:  # type: ignore
        db.add(registration_token)
        db.commit()

    # Get the base URL from the request
    base_url = str(request.base_url)
    # Corrected registration link to point to the SPA
    registration_link = f"{base_url}app/register/{token}"

    logger.info(
        f"Registration token for role '{data.role}' generated by '{current_user.username}'. "
        f"Link: {registration_link}"
    )

    return ActionResponse(
        status="success",
        message="Token generated successfully.",
        redirect_url=f"/app/users?message=Registration link generated: {registration_link}",
    )


@router.get("/validate/{token}", include_in_schema=False)
async def validate_token(
    token: str,
    app_context: AppContext = Depends(get_app_context),
):
    """
    Checks if a registration token is valid.
    """
    with app_context.db.session_manager() as db:  # type: ignore
        registration_token = (
            db.query(RegistrationToken).filter(RegistrationToken.token == token).first()
        )
        if not registration_token or registration_token.expires < int(time.time()):
            return JSONResponse(
                content={"status": "error", "message": "Invalid or expired token."},
                status_code=status.HTTP_404_NOT_FOUND,
            )

        return JSONResponse(
            content={"status": "success", "message": "TokenResponse is valid."}
        )


@router.post("/{token}", include_in_schema=False)
async def register_user(
    token: str,
    data: UserLoginPayload,
    app_context: AppContext = Depends(get_app_context),
):
    """
    Creates a new user from a registration token.
    """
    with app_context.db.session_manager() as db:  # type: ignore
        registration_token = (
            db.query(RegistrationToken).filter(RegistrationToken.token == token).first()
        )
        if not registration_token or registration_token.expires < int(time.time()):
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail={
                    "status": "error",
                    "message": "Invalid or expired registration token.",
                },
            )

        hashed_password = get_password_hash(data.password)
        user = User(
            username=data.username,
            hashed_password=hashed_password,
            role=registration_token.role,
        )

        try:
            db.add(user)
            db.delete(registration_token)  # Delete token after successful registration
            db.commit()
            db.refresh(user)  # Refresh the user object to get its ID if needed later

            logger.info(
                f"UserResponse '{data.username}' registered with role '{registration_token.role}'."
            )

            return JSONResponse(
                content={
                    "status": "success",
                    "message": "Registration successful. Please log in.",
                    "redirect_url": "/app/login?message=Registration successful. Please log in.",
                },
                status_code=status.HTTP_200_OK,  # Explicitly return 200 OK
            )

        except IntegrityError:
            db.rollback()  # Rollback the transaction on database error
            logger.warning(
                f"Registration failed: Username '{data.username}' already exists."
            )
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail={
                    "status": "error",
                    "message": "Username already exists. Please choose a different one.",
                },
            )
        except Exception as e:
            db.rollback()  # Rollback for any other unexpected errors
            logger.error(
                f"An unexpected error occurred during registration: {e}", exc_info=True
            )
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail={
                    "status": "error",
                    "message": "An unexpected server error occurred during registration.",
                },
            )
