# app/modules/tenancy/routes/api/merchant_auth.py
"""
Merchant authentication endpoints.

Implements dual token storage with path restriction:
- Sets HTTP-only cookie with path=/merchants (restricted to merchant routes only)
- Returns token in response for localStorage (API calls)

This prevents merchant cookies from being sent to admin or store routes.
"""

import logging

from fastapi import APIRouter, Depends, Request, Response
from pydantic import BaseModel
from sqlalchemy.orm import Session

from app.api.deps import get_current_merchant_from_cookie_or_header
from app.core.database import get_db
from app.core.environment import should_use_secure_cookies
from app.modules.core.services.auth_service import auth_service
from app.modules.tenancy.models.user_password_reset_token import (
    UserPasswordResetToken,  # noqa: API-007
)
from app.modules.tenancy.schemas.auth import (
    LoginResponse,
    LogoutResponse,
    UserContext,
    UserLogin,
    UserResponse,
)
from app.modules.tenancy.services.user_auth_service import user_auth_service

merchant_auth_router = APIRouter(prefix="/auth")
logger = logging.getLogger(__name__)


@merchant_auth_router.post("/login", response_model=LoginResponse)
def merchant_login(
    user_credentials: UserLogin, response: Response, db: Session = Depends(get_db)
):
    """
    Merchant login endpoint.

    Only allows users who own at least one active merchant to login.
    Returns JWT token for authenticated merchant users.

    Sets token in two places:
    1. HTTP-only cookie with path=/merchants (for browser page navigation)
    2. Response body (for localStorage and API calls)

    The cookie is restricted to /merchants/* routes only to prevent
    it from being sent to admin or store routes.
    """
    # Authenticate user and verify merchant ownership
    login_result = auth_service.login_merchant(db=db, user_credentials=user_credentials)

    logger.info(f"Merchant login successful: {login_result['user'].username}")

    # Set HTTP-only cookie for browser navigation
    # CRITICAL: path=/merchants restricts cookie to merchant routes only
    response.set_cookie(
        key="merchant_token",
        value=login_result["token_data"]["access_token"],
        httponly=True,  # JavaScript cannot access (XSS protection)
        secure=should_use_secure_cookies(),  # HTTPS only in production/staging
        samesite="lax",  # CSRF protection
        max_age=login_result["token_data"]["expires_in"],  # Match JWT expiry
        path="/merchants",  # RESTRICTED TO MERCHANT ROUTES ONLY
    )

    logger.debug(
        f"Set merchant_token cookie with {login_result['token_data']['expires_in']}s expiry "
        f"(path=/merchants, httponly=True, secure={should_use_secure_cookies()})"
    )

    # Also return token in response for localStorage (API calls)
    return LoginResponse(
        access_token=login_result["token_data"]["access_token"],
        token_type=login_result["token_data"]["token_type"],
        expires_in=login_result["token_data"]["expires_in"],
        user=login_result["user"],
    )


@merchant_auth_router.get("/me", response_model=UserResponse)
def get_current_merchant(
    current_user: UserContext = Depends(get_current_merchant_from_cookie_or_header),
):
    """
    Get current authenticated merchant user.

    This endpoint validates the token and ensures the user owns merchants.
    Returns the current user's information.

    Token can come from:
    - Authorization header (API calls)
    - merchant_token cookie (browser navigation, path=/merchants only)
    """
    logger.info(f"Merchant user info requested: {current_user.username}")
    return current_user


@merchant_auth_router.post("/logout", response_model=LogoutResponse)
def merchant_logout(response: Response):
    """
    Merchant logout endpoint.

    Clears the merchant_token cookie.
    Client should also remove token from localStorage.
    """
    logger.info("Merchant logout")

    # Clear the cookie (must match path used when setting)
    response.delete_cookie(
        key="merchant_token",
        path="/merchants",
    )

    logger.debug("Deleted merchant_token cookie (path=/merchants)")

    return LogoutResponse(message="Logged out successfully")


# ============================================================================
# PASSWORD RESET
# ============================================================================


class ForgotPasswordRequest(BaseModel):
    email: str


class ForgotPasswordResponse(BaseModel):
    message: str


class ResetPasswordRequest(BaseModel):
    token: str
    new_password: str


class ResetPasswordResponse(BaseModel):
    message: str


@merchant_auth_router.post("/forgot-password", response_model=ForgotPasswordResponse)
def merchant_forgot_password(
    request: Request,
    body: ForgotPasswordRequest,
    db: Session = Depends(get_db),
):
    """
    Request password reset for merchant user.

    Sends password reset email if account exists.
    Always returns success to prevent email enumeration.
    """
    user, plaintext_token = user_auth_service.request_password_reset(db, body.email)

    if user and plaintext_token:
        try:
            scheme = "https" if should_use_secure_cookies() else "http"
            host = request.headers.get("host", "localhost:8000")
            reset_link = f"{scheme}://{host}/merchants/reset-password?token={plaintext_token}"

            from app.modules.messaging.services.email_service import EmailService

            email_service = EmailService(db)
            email_service.send_template(
                template_code="merchant_password_reset",
                to_email=user.email,
                to_name=user.username,
                language="en",
                variables={
                    "first_name": user.username,
                    "reset_link": reset_link,
                    "expiry_hours": str(UserPasswordResetToken.TOKEN_EXPIRY_HOURS),
                    "platform_name": "Orion",
                },
            )

            db.commit()
            logger.info(f"Password reset email sent to {user.email}")  # noqa: SEC021
        except Exception as e:
            db.rollback()
            logger.error(f"Failed to send password reset email: {e}")  # noqa: SEC021
    else:
        logger.info(f"Password reset requested for non-existent/inactive email {body.email}")  # noqa: SEC021

    return ForgotPasswordResponse(
        message="If an account exists with this email, a password reset link has been sent."
    )


@merchant_auth_router.post("/reset-password", response_model=ResetPasswordResponse)
def merchant_reset_password(
    body: ResetPasswordRequest,
    db: Session = Depends(get_db),
):
    """
    Reset merchant user password using reset token.

    Validates the token and sets the new password.
    """
    user = user_auth_service.reset_password(db, body.token, body.new_password)
    db.commit()

    logger.info(f"Password reset completed for user {user.id} ({user.email})")  # noqa: SEC021

    return ResetPasswordResponse(
        message="Password reset successfully. You can now log in with your new password."
    )
