"""
FastAPI integration example for Kilit.

This example shows how to use Kilit to manage encrypted secrets
in a FastAPI application.
"""

from fastapi import FastAPI, Depends
from pydantic import BaseSettings
from kilit import Credentials
from typing import Optional

# Load credentials at module level
creds = Credentials("config/credentials.json.enc")


# Pydantic Settings with Kilit
# =============================

class Settings(BaseSettings):
    """Application settings loaded from Kilit."""
    
    # App configuration
    app_name: str = "My FastAPI App"
    debug: bool = False
    
    # Database
    database_url: str
    
    # Redis
    redis_url: str = "redis://localhost:6379/0"
    
    # JWT
    jwt_secret_key: str
    jwt_algorithm: str = "HS256"
    jwt_access_token_expire_minutes: int = 30
    
    # Third-party APIs
    stripe_secret_key: str
    stripe_publishable_key: str
    
    # AWS
    aws_access_key_id: str
    aws_secret_access_key: str
    aws_bucket_name: str
    
    class Config:
        case_sensitive = False


def get_settings() -> Settings:
    """Load settings from Kilit credentials."""
    return Settings(
        app_name=creds.get("app.name", "My FastAPI App"),
        debug=creds.get("app.debug", False),
        database_url=(
            f"postgresql://{creds.require('database.user')}:"
            f"{creds.require('database.password')}@"
            f"{creds.get('database.host', 'localhost')}:"
            f"{creds.get('database.port', 5432)}/"
            f"{creds.get('database.name', 'myapp_db')}"
        ),
        redis_url=creds.get("redis.url", "redis://localhost:6379/0"),
        jwt_secret_key=creds.require("jwt.secret_key"),
        jwt_algorithm=creds.get("jwt.algorithm", "HS256"),
        jwt_access_token_expire_minutes=creds.get("jwt.access_token_expire_minutes", 30),
        stripe_secret_key=creds.require("stripe.secret_key"),
        stripe_publishable_key=creds.require("stripe.publishable_key"),
        aws_access_key_id=creds.require("aws.access_key_id"),
        aws_secret_access_key=creds.require("aws.secret_access_key"),
        aws_bucket_name=creds.get("aws.bucket_name", "my-bucket"),
    )


# Initialize FastAPI app
# ======================

app = FastAPI(title="Kilit FastAPI Example")


# Dependency injection
# ====================

@app.get("/")
async def root(settings: Settings = Depends(get_settings)):
    """Root endpoint with settings dependency."""
    return {
        "message": f"Welcome to {settings.app_name}",
        "debug": settings.debug,
    }


@app.get("/config")
async def get_config(settings: Settings = Depends(get_settings)):
    """Expose non-sensitive configuration."""
    return {
        "app_name": settings.app_name,
        "stripe_publishable_key": settings.stripe_publishable_key,
        "jwt_algorithm": settings.jwt_algorithm,
    }


# Database connection example
# ===========================

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

def get_db_engine(settings: Settings = Depends(get_settings)):
    """Create database engine from settings."""
    engine = create_engine(settings.database_url)
    return engine


# Redis connection example
# ========================

import redis

def get_redis_client(settings: Settings = Depends(get_settings)):
    """Create Redis client from settings."""
    return redis.from_url(settings.redis_url)


# JWT authentication example
# ==========================

from datetime import datetime, timedelta
from jose import JWTError, jwt
from fastapi import HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials

security = HTTPBearer()


def create_access_token(data: dict, settings: Settings) -> str:
    """Create JWT access token."""
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=settings.jwt_access_token_expire_minutes)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(
        to_encode,
        settings.jwt_secret_key,
        algorithm=settings.jwt_algorithm
    )
    return encoded_jwt


def verify_token(
    credentials: HTTPAuthorizationCredentials = Depends(security),
    settings: Settings = Depends(get_settings)
) -> dict:
    """Verify JWT token."""
    try:
        payload = jwt.decode(
            credentials.credentials,
            settings.jwt_secret_key,
            algorithms=[settings.jwt_algorithm]
        )
        return payload
    except JWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Could not validate credentials",
        )


@app.post("/login")
async def login(username: str, password: str, settings: Settings = Depends(get_settings)):
    """Login endpoint that returns JWT token."""
    # Verify credentials (simplified example)
    if username == "admin" and password == creds.require("admin.password"):
        access_token = create_access_token(
            data={"sub": username},
            settings=settings
        )
        return {"access_token": access_token, "token_type": "bearer"}
    raise HTTPException(status_code=401, detail="Invalid credentials")


@app.get("/protected")
async def protected_route(token_data: dict = Depends(verify_token)):
    """Protected endpoint that requires authentication."""
    return {"message": f"Hello, {token_data['sub']}!"}


# Startup/shutdown events
# =======================

@app.on_event("startup")
async def startup_event():
    """Initialize resources on startup."""
    settings = get_settings()
    print(f"Starting {settings.app_name}")
    print(f"Database: {settings.database_url.split('@')[1]}")  # Don't log password!
    print(f"Redis: {settings.redis_url}")


@app.on_event("shutdown")
async def shutdown_event():
    """Cleanup resources on shutdown."""
    print("Shutting down...")


# Example credentials.json structure:
# ====================================
"""
{
  "app": {
    "name": "My FastAPI App",
    "debug": false
  },
  "database": {
    "user": "myapp_user",
    "password": "super-secret-password",
    "host": "localhost",
    "port": 5432,
    "name": "myapp_db"
  },
  "redis": {
    "url": "redis://localhost:6379/0"
  },
  "jwt": {
    "secret_key": "your-jwt-secret-key-here",
    "algorithm": "HS256",
    "access_token_expire_minutes": 30
  },
  "stripe": {
    "secret_key": "sk_live_...",
    "publishable_key": "pk_live_..."
  },
  "aws": {
    "access_key_id": "AKIAIOSFODNN7EXAMPLE",
    "secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
    "bucket_name": "my-production-bucket"
  },
  "admin": {
    "password": "admin-password-here"
  }
}
"""


# Setup instructions:
# ===================
"""
1. Initialize encrypted credentials:
   $ kilit init --path config/credentials.json.enc

2. Edit credentials:
   $ kilit edit --path config/credentials.json.enc

3. Add to .gitignore:
   config/master.key

4. Run FastAPI app:
   $ export KILIT_MASTER_KEY="your-master-key"
   $ uvicorn fastapi_example:app --reload

5. For development, use local master key file:
   $ uvicorn fastapi_example:app --reload
   (reads from config/master.key automatically)

6. Access API docs:
   http://localhost:8000/docs
"""


if __name__ == "__main__":
    import uvicorn
    settings = get_settings()
    uvicorn.run(app, host="0.0.0.0", port=8000, debug=settings.debug)
