# 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, Request, Depends, Form, status, HTTPException
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
from sqlalchemy.exc import IntegrityError
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel

from ...db.models import User, RegistrationToken
from ..dependencies import get_templates, get_app_context
from ..auth_utils import (
    get_current_user,
    get_current_user_optional,
    get_admin_user,
    get_password_hash,
)
from ..schemas import User as UserSchema
from ...context import AppContext

logger = logging.getLogger(__name__)

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


class GenerateTokenRequest(BaseModel):
    """
    Request payload for generating a registration token.

    Attributes:
        role (str): The role to assign to the user registering with this token.
    """

    role: str


@router.post("/generate-token", include_in_schema=False)
async def generate_token(
    request: Request,
    data: GenerateTokenRequest,
    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:
        db.add(registration_token)
        db.commit()

    # Get the base URL from the request
    base_url = str(request.base_url)
    registration_link = f"{base_url}register/{token}"

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

    return {
        "status": "success",
        "redirect_url": f"/users?message=Registration link generated: {registration_link}",
    }


@router.get("/{token}", response_class=HTMLResponse, include_in_schema=False)
async def registration_page(
    request: Request,
    token: str,
    current_user: UserSchema = Depends(get_current_user_optional),
    app_context: AppContext = Depends(get_app_context),
    templates: Jinja2Templates = Depends(get_templates),
):
    """
    Serves the registration page if the token is valid.
    """
    with app_context.db.session_manager() as db:
        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="Invalid or expired registration token.",
            )

    return templates.TemplateResponse(
        request,
        "register.html",
        {"token": token, "current_user": current_user},
    )


class RegisterUserRequest(BaseModel):
    """
    Request payload for user registration.

    Attributes:
        username (str): The desired username.
        password (str): The desired password.
    """

    username: str
    password: str


@router.post("/{token}", include_in_schema=False)
async def register_user(
    token: str,
    data: RegisterUserRequest,
    app_context: AppContext = Depends(get_app_context),
):
    """
    Creates a new user from a registration token.
    """
    with app_context.db.session_manager() as db:
        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"User '{data.username}' registered with role '{registration_token.role}'."
            )

            return JSONResponse(
                content={
                    "status": "success",
                    "message": "Registration successful. Please log in.",
                    "redirect_url": "/auth/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.",
                },
            )
