"""
Admin router for admin authentication and management
"""

import os
import bcrypt
import jwt
from datetime import datetime, timedelta
from typing import List, Optional
from fastapi import APIRouter, HTTPException, Depends, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session
from pydantic import BaseModel

from models.admin import (
    Admin, AdminRole, AdminLogin, AdminCreate, AdminUpdate,
    PasswordReset, PasswordResetConfirm, TokenResponse, AdminResponse
)

from core.database import get_db

router = APIRouter(prefix="/admin", tags=["admin"])

# In-memory storage for password reset tokens (temporary)
reset_tokens = {}

# JWT settings
SECRET_KEY = os.getenv("SECRET_KEY", "your-secret-key-here")  # Use environment variable
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

security = HTTPBearer()

def hash_password(password: str) -> str:
    """Hash a password using bcrypt"""
    return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')

def verify_password(password: str, hashed: str) -> bool:
    """Verify a password against its hash"""
    return bcrypt.checkpw(password.encode('utf-8'), hashed.encode('utf-8'))

def create_access_token(data: dict):
    """Create JWT access token"""
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

def get_current_admin(
    credentials: HTTPAuthorizationCredentials = Depends(security),
    db: Session = Depends(get_db)
) -> Admin:
    """Get current admin from JWT token"""
    try:
        payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise HTTPException(status_code=401, detail="Invalid token")
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token expired")
    except jwt.JWTError:
        raise HTTPException(status_code=401, detail="Invalid token")

    admin = db.query(Admin).filter(Admin.username == username).first()
    if admin is None:
        raise HTTPException(status_code=401, detail="Admin not found")

    if not admin.is_active:
        raise HTTPException(status_code=401, detail="Admin account is inactive")

    return admin

def require_admin_role(required_role: AdminRole):
    """Dependency to require specific admin role"""
    def role_checker(admin: Admin = Depends(get_current_admin)):
        if admin.role != required_role:
            raise HTTPException(
                status_code=403,
                detail=f"Access denied. Required role: {required_role.value}"
            )
        return admin
    return role_checker

# Initialize with a default administrator (for demo)
# This will be handled in main.py or through database migration

@router.post("/login", response_model=TokenResponse)
async def login(login_data: AdminLogin, db: Session = Depends(get_db)):
    """Admin login endpoint"""
    try:
        admin = db.query(Admin).filter(Admin.username == login_data.username).first()
        if not admin or not verify_password(login_data.password, admin.password_hash):
            raise HTTPException(status_code=401, detail="Invalid credentials")

        if not admin.is_active:
            raise HTTPException(status_code=401, detail="Account is inactive")

        access_token = create_access_token(data={"sub": admin.username})

        return TokenResponse(
            access_token=access_token,
            admin={
                "id": admin.id,
                "username": admin.username,
                "email": admin.email,
                "role": admin.role.value,
                "permissions": admin.permissions,
                "is_active": admin.is_active
            }
        )
    except HTTPException:
        raise
    except Exception as e:
        print(f"Login error for user {login_data.username}: {str(e)}")
        raise HTTPException(status_code=500, detail="Internal server error")

@router.post("/logout")
async def logout(current_admin: Admin = Depends(get_current_admin)):
    """Admin logout endpoint"""
    # In a real implementation, you might blacklist the token
    # For now, just return success
    return {"message": "Logged out successfully"}

@router.post("/forgot-password")
async def forgot_password(reset_data: PasswordReset, db: Session = Depends(get_db)):
    """Forgot password endpoint - sends reset token"""
    admin = db.query(Admin).filter(Admin.email == reset_data.email).first()

    if not admin:
        # Don't reveal if email exists or not for security
        return {"message": "If the email exists, a reset token has been sent"}

    # Generate a simple reset token (in production, use secure method)
    reset_token = f"reset_{admin.username}_{datetime.utcnow().timestamp()}"
    reset_tokens[reset_token] = admin.username

    # In production, send email with token
    print(f"Reset token for {admin.email}: {reset_token}")

    return {"message": "If the email exists, a reset token has been sent"}

@router.post("/reset-password")
async def reset_password(reset_confirm: PasswordResetConfirm, db: Session = Depends(get_db)):
    """Reset password with token"""
    username = reset_tokens.get(reset_confirm.token)
    if not username:
        raise HTTPException(status_code=400, detail="Invalid or expired reset token")

    admin = db.query(Admin).filter(Admin.username == username).first()
    if not admin:
        raise HTTPException(status_code=400, detail="Admin not found")

    admin.password_hash = hash_password(reset_confirm.new_password)
    admin.updated_at = datetime.utcnow()
    db.commit()

    # Remove used token
    del reset_tokens[reset_confirm.token]

    return {"message": "Password reset successfully"}

@router.get("/users", response_model=List[AdminResponse])
async def get_admins(
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(require_admin_role(AdminRole.ADMINISTRATOR))
):
    """Get all admins (Administrator only)"""
    admins = db.query(Admin).all()
    return [
        AdminResponse(
            id=a.id,
            username=a.username,
            email=a.email,
            role=a.role,
            permissions=a.permissions,
            is_active=a.is_active,
            created_at=a.created_at,
            updated_at=a.updated_at
        )
        for a in admins
    ]

@router.post("/users", response_model=AdminResponse)
async def create_admin(
    admin_data: AdminCreate,
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(require_admin_role(AdminRole.ADMINISTRATOR))
):
    """Create new admin (Administrator only)"""
    # Check if username already exists
    existing_username = db.query(Admin).filter(Admin.username == admin_data.username).first()
    if existing_username:
        raise HTTPException(status_code=400, detail="Username already exists")

    # Check if email is unique
    existing_email = db.query(Admin).filter(Admin.email == admin_data.email).first()
    if existing_email:
        raise HTTPException(status_code=400, detail="Email already exists")

    # Ensure permissions is a list
    permissions = admin_data.permissions
    if permissions is None:
        permissions_list = None
    elif isinstance(permissions, str):
        permissions_list = [permissions]
    else:
        permissions_list = permissions

    new_admin = Admin(
        username=admin_data.username,
        email=admin_data.email,
        password_hash=hash_password(admin_data.password),
        role=admin_data.role,
        permissions=permissions_list,
        is_active=True,
        created_at=datetime.utcnow(),
        updated_at=datetime.utcnow()
    )

    db.add(new_admin)
    db.commit()
    db.refresh(new_admin)

    return AdminResponse(
        id=new_admin.id,
        username=new_admin.username,
        email=new_admin.email,
        role=new_admin.role,
        permissions=new_admin.permissions,
        is_active=new_admin.is_active,
        created_at=new_admin.created_at,
        updated_at=new_admin.updated_at
    )

@router.put("/users/{admin_id}", response_model=AdminResponse)
async def update_admin(
    admin_id: int,
    update_data: AdminUpdate,
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(require_admin_role(AdminRole.ADMINISTRATOR))
):
    """Update admin (Administrator only)"""
    admin = db.query(Admin).filter(Admin.id == admin_id).first()
    if not admin:
        raise HTTPException(status_code=404, detail="Admin not found")

    # Update fields
    if update_data.username is not None:
        # Check if new username already exists (excluding current admin)
        existing_username = db.query(Admin).filter(
            Admin.username == update_data.username,
            Admin.id != admin_id
        ).first()
        if existing_username:
            raise HTTPException(status_code=400, detail="Username already exists")
        admin.username = update_data.username

    if update_data.email is not None:
        # Check email uniqueness (excluding current admin)
        existing_email = db.query(Admin).filter(
            Admin.email == update_data.email,
            Admin.id != admin_id
        ).first()
        if existing_email:
            raise HTTPException(status_code=400, detail="Email already exists")
        admin.email = update_data.email

    if update_data.role is not None:
        admin.role = update_data.role

    if update_data.permissions is not None:
        admin.permissions = update_data.permissions

    if update_data.is_active is not None:
        admin.is_active = update_data.is_active

    admin.updated_at = datetime.utcnow()
    db.commit()
    db.refresh(admin)

    return AdminResponse(
        id=admin.id,
        username=admin.username,
        email=admin.email,
        role=admin.role,
        permissions=admin.permissions,
        is_active=admin.is_active,
        created_at=admin.created_at,
        updated_at=admin.updated_at
    )

@router.delete("/users/{admin_id}")
async def delete_admin(
    admin_id: int,
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(require_admin_role(AdminRole.ADMINISTRATOR))
):
    """Delete admin (Administrator only)"""
    if current_admin.id == admin_id:
        raise HTTPException(status_code=400, detail="Cannot delete your own account")

    admin = db.query(Admin).filter(Admin.id == admin_id).first()
    if not admin:
        raise HTTPException(status_code=404, detail="Admin not found")

    db.delete(admin)
    db.commit()

    return {"message": "Admin deleted successfully"}


