"""
Authentication routes for HIEROMEM SaaS.

Handles user signup and login, returning JWT tokens and user info.
"""

from __future__ import annotations

import secrets
import hashlib
from datetime import datetime, timedelta
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, status, Header
from pydantic import BaseModel, EmailStr
from werkzeug.security import generate_password_hash, check_password_hash
import jwt

from hieromem_api.tenants import Tenant, get_tenant_registry
from hieromem_api.settings import get_settings

router = APIRouter(prefix="/auth", tags=["Authentication"])


class UserSignup(BaseModel):
    email: EmailStr
    password: str
    name: Optional[str] = None


class UserLogin(BaseModel):
    email: EmailStr
    password: str


class AuthResponse(BaseModel):
    token: str
    user: dict


def _get_jwt_secret() -> str:
    settings = get_settings()
    if settings.encryption_key:
        return settings.encryption_key
    if settings.debug:
        return "insecure-dev-secret"
    raise RuntimeError(
        "HIEROMEM_ENCRYPTION_KEY must be set for JWT signing in non-debug environments."
    )


def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})

    # Use encryption key as JWT secret if no specific JWT secret is set
    secret = _get_jwt_secret()
    encoded_jwt = jwt.encode(to_encode, secret, algorithm="HS256")
    return encoded_jwt


def verify_token(authorization: str = Header(None)) -> str:
    if not authorization or not authorization.startswith("Bearer "):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Missing or invalid authorization header"
        )
    token = authorization.replace("Bearer ", "")
    secret = _get_jwt_secret()
    try:
        payload = jwt.decode(token, secret, algorithms=["HS256"])
        return payload["sub"]
    except jwt.ExpiredSignatureError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Token has expired"
        )
    except jwt.InvalidTokenError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token"
        )


@router.post("/signup", response_model=AuthResponse)
async def signup(user_data: UserSignup):
    """
    Register a new user (tenant).

    Creates a new tenant with the provided email and password.
    Returns an access token and user info.
    """
    registry = get_tenant_registry()

    # Check if user already exists (by tenant_id/email)
    existing = registry.list_by_tenant(user_data.email)
    if existing:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Email already registered"
        )

    # Generate API key
    api_key = f"hm_{secrets.token_urlsafe(32)}"
    key_hash = hashlib.sha256(api_key.encode("utf-8")).hexdigest()

    # Hash password
    password_hash = generate_password_hash(user_data.password)

    # Create tenant
    new_tenant = Tenant(
        tenant_id=user_data.email,
        api_key=api_key,
        api_key_hash=key_hash,
        password_hash=password_hash,
        name=user_data.name,
        tier="free",
        role="admin"
    )

    registry.upsert(new_tenant)

    # Create access token
    access_token = create_access_token(
        data={"sub": new_tenant.tenant_id, "tier": new_tenant.tier},
        expires_delta=timedelta(days=7)  # Long session for dashboard
    )

    return AuthResponse(
        token=access_token,
        user={
            "id": new_tenant.tenant_id,  # Frontend expects 'id'
            "email": new_tenant.tenant_id,
            "name": new_tenant.name,
            "tier": new_tenant.tier,
            "api_key": api_key  # Return API key on signup so they can save it
        }
    )


@router.post("/login", response_model=AuthResponse)
async def login(user_data: UserLogin):
    """
    Login with email and password.

    Verifies credentials and returns an access token.
    """
    registry = get_tenant_registry()

    # Find tenant by email
    tenants = registry.list_by_tenant(user_data.email)
    if not tenants:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid email or password",
            headers={"WWW-Authenticate": "Bearer"},
        )

    # In our model, a "user" is a tenant. We take the first record (primary).
    # Ideally, we'd have a separate User model, but for now Tenant = User.
    tenant = tenants[0]

    if not tenant.password_hash or not check_password_hash(tenant.password_hash, user_data.password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid email or password",
            headers={"WWW-Authenticate": "Bearer"},
        )

    # Create access token
    access_token = create_access_token(
        data={"sub": tenant.tenant_id, "tier": tenant.tier},
        expires_delta=timedelta(days=7)
    )

    return AuthResponse(
        token=access_token,
        user={
            "id": tenant.tenant_id,
            "email": tenant.tenant_id,
            "name": tenant.name,
            "tier": tenant.tier,
            # Don't return API key on login, they can get it from dashboard
        }
    )


@router.post("/logout")
async def logout():
    """Logout endpoint (stateless JWT, so just returns success)."""
    return {"message": "Logged out successfully"}


@router.get("/me")
async def get_me(user_id: str = Depends(verify_token)):
    """Get current user info."""
    registry = get_tenant_registry()
    tenants = registry.list_by_tenant(user_id)

    if not tenants:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )

    tenant = tenants[0]
    return {
        "id": tenant.tenant_id,
        "email": tenant.tenant_id,
        "name": tenant.name,
        "tier": tenant.tier
    }
