import hashlib
import logging
from datetime import datetime
from typing import List, Optional

from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel, Field
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession

from database import get_db
from models import User

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/api/users", tags=["users"])


def hash_password(password: str) -> str:
    """Hash password for basic storage."""
    return hashlib.sha256(password.encode("utf-8")).hexdigest()


ALL_MODULE_KEYS = ["dashboard", "domains", "cloudflare", "hosting", "dns", "accounts", "users", "settings"]


# ---------------------------------------------------------------------------
# Pydantic Schemas
# ---------------------------------------------------------------------------


class LoginRequest(BaseModel):
    username_or_email: str
    password: str


class UserCreate(BaseModel):
    username: str = Field(..., min_length=1, max_length=64)
    email: str = Field(..., min_length=3, max_length=255)
    password: Optional[str] = Field("123456")
    role: Optional[str] = Field("developer")
    custom_role_name: Optional[str] = None
    permissions: Optional[List[str]] = Field(
        default_factory=lambda: ["domains", "cloudflare", "hosting", "dns"]
    )


class UserUpdate(BaseModel):
    email: Optional[str] = None
    password: Optional[str] = None
    role: Optional[str] = None
    custom_role_name: Optional[str] = None
    permissions: Optional[List[str]] = None
    is_active: Optional[bool] = None


class UserResponse(BaseModel):
    id: int
    username: str
    email: str
    role: str
    custom_role_name: Optional[str] = None
    permissions: List[str]
    is_active: bool
    created_at: datetime
    updated_at: datetime


def format_user_response(user: User) -> UserResponse:
    """Format ORM model into UserResponse with permissions list."""
    perms_raw = user.permissions or ""
    perms_list = [p.strip() for p in perms_raw.split(",") if p.strip()]

    return UserResponse(
        id=user.id,
        username=user.username,
        email=user.email,
        role=user.role or "developer",
        custom_role_name=user.custom_role_name,
        permissions=perms_list if perms_list else ["domains", "cloudflare", "hosting", "dns"],
        is_active=user.is_active,
        created_at=user.created_at,
        updated_at=user.updated_at,
    )


# ---------------------------------------------------------------------------
# Seeding Helper
# ---------------------------------------------------------------------------


async def seed_default_users_if_empty(db: AsyncSession) -> None:
    """Ensure Super Admin account ('admin') exists with full permissions."""
    try:
        stmt = select(User).where(User.username == "admin")
        res = await db.execute(stmt)
        admin_user = res.scalars().first()

        if not admin_user:
            logger.info("Seeding Super Admin 'admin' into database...")
            admin_user = User(
                username="admin",
                email="admin@domainplatform.local",
                password_hash=hash_password("admin123"),
                role="admin",
                custom_role_name="Super Administrator",
                permissions="dashboard,domains,cloudflare,hosting,dns,accounts,users,settings",
                is_active=True,
            )
            db.add(admin_user)
            await db.commit()
        else:
            # Ensure Super Admin always retains full module access
            admin_user.role = "admin"
            admin_user.permissions = "dashboard,domains,cloudflare,hosting,dns,accounts,users,settings"
            admin_user.is_active = True
            await db.commit()
    except Exception as exc:
        logger.error("User seeding error: %s", exc)
        await db.rollback()


# ---------------------------------------------------------------------------
# Router Endpoints
# ---------------------------------------------------------------------------


@router.post("/login", response_model=UserResponse)
async def login_user(payload: LoginRequest, db: AsyncSession = Depends(get_db)):
    """Authenticate user credentials and return user profile & granted permissions."""
    await seed_default_users_if_empty(db)

    query_str = payload.username_or_email.strip().lower()
    pass_hash = hash_password(payload.password)

    stmt = select(User).where(
        (func.lower(User.username) == query_str) | (func.lower(User.email) == query_str)
    )
    res = await db.execute(stmt)
    user = res.scalars().first()

    if not user:
        raise HTTPException(status_code=401, detail="Invalid username or password.")
    if user.password_hash != pass_hash:
        raise HTTPException(status_code=401, detail="Invalid username or password.")
    if not user.is_active:
        raise HTTPException(status_code=403, detail="Your user account is deactivated.")

    return format_user_response(user)


@router.get("", response_model=List[UserResponse])
async def list_users(db: AsyncSession = Depends(get_db)):
    """List all registered system users, custom roles, and assigned permissions."""
    await seed_default_users_if_empty(db)
    stmt = select(User).order_by(User.id.asc())
    res = await db.execute(stmt)
    users = res.scalars().all()
    return [format_user_response(u) for u in users]


@router.post("", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
async def create_user(payload: UserCreate, db: AsyncSession = Depends(get_db)):
    """Create a new user with custom role title and modular feature permissions."""
    username_clean = payload.username.strip()
    email_clean = payload.email.strip().lower()

    if not username_clean:
        raise HTTPException(status_code=400, detail="Username is required.")
    if not email_clean:
        raise HTTPException(status_code=400, detail="Email is required.")

    # Check username uniqueness
    stmt = select(User).where(User.username == username_clean)
    res = await db.execute(stmt)
    if res.scalars().first():
        raise HTTPException(status_code=400, detail=f"Username '{username_clean}' is already taken.")

    # Check email uniqueness
    stmt = select(User).where(User.email == email_clean)
    res = await db.execute(stmt)
    if res.scalars().first():
        raise HTTPException(status_code=400, detail=f"Email '{email_clean}' is already registered.")

    perms_list = payload.permissions if payload.permissions is not None else ["domains", "cloudflare", "hosting", "dns"]
    perms_str = ",".join([p.strip().lower() for p in perms_list if p.strip()])

    user = User(
        username=username_clean,
        email=email_clean,
        password_hash=hash_password(payload.password or "123456"),
        role=(payload.role or "developer").lower().strip(),
        custom_role_name=payload.custom_role_name.strip() if payload.custom_role_name and payload.custom_role_name.strip() else None,
        permissions=perms_str or "domains,cloudflare,hosting,dns",
        is_active=True,
    )

    db.add(user)
    await db.commit()
    await db.refresh(user)

    return format_user_response(user)


@router.get("/{user_id}", response_model=UserResponse)
async def get_user(user_id: int, db: AsyncSession = Depends(get_db)):
    """Get single user by ID."""
    user = await db.get(User, user_id)
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return format_user_response(user)


@router.put("/{user_id}", response_model=UserResponse)
async def update_user(user_id: int, payload: UserUpdate, db: AsyncSession = Depends(get_db)):
    """Update user role, custom title, permissions list, or active status."""
    user = await db.get(User, user_id)
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    if payload.email is not None and payload.email.strip():
        user.email = payload.email.strip().lower()
    if payload.role is not None and payload.role.strip():
        user.role = payload.role.lower().strip()
    if payload.custom_role_name is not None:
        user.custom_role_name = payload.custom_role_name.strip() if payload.custom_role_name.strip() else None
    if payload.permissions is not None:
        user.permissions = ",".join([p.strip().lower() for p in payload.permissions if p.strip()])
    if payload.is_active is not None:
        user.is_active = payload.is_active
    if payload.password and payload.password.strip():
        user.password_hash = hash_password(payload.password)

    await db.commit()
    await db.refresh(user)

    return format_user_response(user)


@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_user(user_id: int, db: AsyncSession = Depends(get_db)):
    """Delete a user account."""
    user = await db.get(User, user_id)
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    if user.username == "admin":
        raise HTTPException(status_code=400, detail="Cannot delete Super Admin 'admin' user account.")

    await db.delete(user)
    await db.commit()
    return None
