import os
import shutil
import uuid
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select

from database import get_db
from models import User, SystemSetting, Role, AuditLog, Holiday, Project
from schemas import SystemSettingResponse, UserResponse, UserCreate, UserUpdate, HolidayCreate, HolidayResponse
from auth import require_roles, get_password_hash, get_current_active_user
from typing import List
from sqlalchemy.orm import selectinload

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

@router.get("/settings", response_model=list[SystemSettingResponse])
async def get_settings(
    db: AsyncSession = Depends(get_db), 
    current_user: User = Depends(require_roles(["Administrador"]))
):
    stmt = select(SystemSetting).where(SystemSetting.company_id == current_user.company_id)
    result = await db.execute(stmt)
    return result.scalars().all()

@router.post("/settings/logo")
async def upload_logo(
    file: UploadFile = File(...),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador"]))
):
    upload_dir = "uploads/logos"
    os.makedirs(upload_dir, exist_ok=True)
    
    ext = file.filename.split('.')[-1]
    new_filename = f"logo_{uuid.uuid4().hex}.{ext}"
    file_path = os.path.join(upload_dir, new_filename)
    
    with open(file_path, "wb") as buffer:
        shutil.copyfileobj(file.file, buffer)
        
    stmt = select(SystemSetting).where(SystemSetting.key == "app_logo").where(SystemSetting.company_id == current_user.company_id)
    result = await db.execute(stmt)
    setting = result.scalar_one_or_none()
    
    # We could delete the old logo file if setting exists, but let's keep it simple for now
    
    if setting:
        setting.value = "/" + file_path.replace("\\", "/") # Ensure forward slashes for web
        setting.company_id = current_user.company_id
    else:
        setting = SystemSetting(key="app_logo", value="/" + file_path.replace("\\", "/"), company_id=current_user.company_id)
        db.add(setting)
        
    await db.commit()
    return {"status": "success", "logo_url": setting.value}

@router.delete("/settings/logo")
async def delete_logo(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador"]))
):
    stmt = select(SystemSetting).where(SystemSetting.company_id == current_user.company_id).where(SystemSetting.key == "app_logo")
    result = await db.execute(stmt)
    setting = result.scalar_one_or_none()
    if setting:
        if setting.value and setting.value.startswith("/uploads/logos/"):
            try:
                # remove leading slash
                file_path = setting.value[1:]
                if os.path.exists(file_path):
                    os.remove(file_path)
            except Exception:
                pass
        await db.delete(setting)
        await db.commit()
    return {"status": "success"}

@router.post("/settings/{key}")
async def update_setting(
    key: str, 
    value: str, 
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador"]))
):
    stmt = select(SystemSetting).where(SystemSetting.key == key).where(SystemSetting.company_id == current_user.company_id)
    result = await db.execute(stmt)
    setting = result.scalar_one_or_none()
    
    if setting:
        setting.value = value
        setting.company_id = current_user.company_id
    else:
        setting = SystemSetting(key=key, value=value, company_id=current_user.company_id)
        db.add(setting)
        
    await db.commit()
    return {"status": "success", "key": key, "value": value}

# --- USER MANAGEMENT ---

@router.get("/users", response_model=list[UserResponse])
async def admin_get_users(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador"]))
):
    stmt = select(User).where(User.company_id == current_user.company_id).options(selectinload(User.roles), selectinload(User.viewable_projects))
    result = await db.execute(stmt)
    return result.scalars().all()

@router.post("/users", response_model=UserResponse)
async def admin_create_user(
    user: UserCreate, 
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador"]))
):
    stmt = select(User).where(User.company_id == current_user.company_id).where(User.username == user.username)
    result = await db.execute(stmt)
    if result.scalar_one_or_none():
        raise HTTPException(status_code=400, detail="El nombre de usuario ya existe")
        
    hashed_password = get_password_hash(user.password)
    db_user = User(username=user.username, email=user.email, hashed_password=hashed_password, company_id=current_user.company_id)
    
    if user.viewable_project_ids:
        proj_stmt = select(Project).where(Project.id.in_(user.viewable_project_ids))
        projs = await db.execute(proj_stmt)
        db_user.viewable_projects = projs.scalars().all()

    db.add(db_user)
    
    # Handle role
    selected_role_name = user.role if user.role else ("Administrador" if user.is_admin else "Visualizador")
    role_stmt = select(Role).where(Role.name == selected_role_name)
    role_res = await db.execute(role_stmt)
    target_role = role_res.scalar_one_or_none()
    if not target_role:
        target_role = Role(name=selected_role_name, description=f"Rol de {selected_role_name}")
        db.add(target_role)
    db_user.roles.append(target_role)
        
    audit = AuditLog(
        user_id=current_user.id,
        username=current_user.username,
        action=f"Creó al usuario '{user.username}'"
    )
    db.add(audit)
        
    await db.commit()
    await db.refresh(db_user)
    
    # Reload with relationships
    stmt_reload = select(User).where(User.company_id == current_user.company_id).options(selectinload(User.roles), selectinload(User.viewable_projects)).where(User.id == db_user.id)
    res_reload = await db.execute(stmt_reload)
    return res_reload.scalar_one()

@router.put("/users/{user_id}", response_model=UserResponse)
async def admin_update_user(
    user_id: int,
    user: UserUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador"]))
):
    stmt = select(User).where(User.company_id == current_user.company_id).options(selectinload(User.roles), selectinload(User.viewable_projects)).where(User.id == user_id)
    result = await db.execute(stmt)
    db_user = result.scalar_one_or_none()
    if not db_user:
        raise HTTPException(status_code=404, detail="Usuario no encontrado")
        
    if (db_user.id == 1 or db_user.username in ["admin", "jampuero"]) and user.username != db_user.username:
        raise HTTPException(status_code=400, detail="No se puede cambiar el nombre de este usuario protegido")
        
    db_user.username = user.username
    db_user.email = user.email
    if user.password:
        db_user.hashed_password = get_password_hash(user.password)
        
    if user.viewable_project_ids is not None:
        proj_stmt = select(Project).where(Project.id.in_(user.viewable_project_ids))
        projs = await db.execute(proj_stmt)
        db_user.viewable_projects = projs.scalars().all()
        
    # Handle role
    if user_id == 1 and user.role and user.role != "Administrador":
        raise HTTPException(status_code=400, detail="No se puede quitar el rol admin al usuario principal")
        
    selected_role_name = user.role if user.role else ("Administrador" if user.is_admin else "Visualizador")
    role_stmt = select(Role).where(Role.name == selected_role_name)
    role_res = await db.execute(role_stmt)
    target_role = role_res.scalar_one_or_none()
    if not target_role:
        target_role = Role(name=selected_role_name, description=f"Rol de {selected_role_name}")
        db.add(target_role)
    db_user.roles = [target_role]
        
    audit = AuditLog(
        user_id=current_user.id,
        username=current_user.username,
        action=f"Actualizó la configuración del usuario '{user.username}'"
    )
    db.add(audit)
        
    await db.commit()
    await db.refresh(db_user)
    return db_user

@router.delete("/users/{user_id}")
async def admin_delete_user(
    user_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador"]))
):
    if user_id == 1:
        raise HTTPException(status_code=403, detail="No se puede eliminar al administrador principal")
        
    stmt = select(User).where(User.company_id == current_user.company_id).where(User.id == user_id)
    result = await db.execute(stmt)
    db_user = result.scalar_one_or_none()
    if not db_user:
        raise HTTPException(status_code=404, detail="Usuario no encontrado")
        
    if db_user.username == "jampuero":
        raise HTTPException(status_code=403, detail="El usuario 'jampuero' está protegido y no puede ser eliminado")
        
    await db.delete(db_user)
    
    audit = AuditLog(
        user_id=current_user.id,
        username=current_user.username,
        action=f"Eliminó al usuario '{db_user.username}'"
    )
    db.add(audit)
    
    await db.commit()
    return {"status": "success"}

# --- AUDIT & ONLINE USERS ---
from datetime import datetime, timedelta

@router.get("/online-users")
async def get_online_users(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador"]))
):
    try:
        five_mins_ago = datetime.utcnow() - timedelta(minutes=5)
        stmt = select(User).where(User.company_id == current_user.company_id).where(User.last_active > five_mins_ago).order_by(User.last_active.desc())
        result = await db.execute(stmt)
        users = result.scalars().all()
        return [
            {
                "id": u.id,
                "username": u.username,
                "last_active": u.last_active.isoformat() if u.last_active else None
            }
            for u in users
        ]
    except Exception as e:
        import traceback
        traceback.print_exc()
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/audit-logs")
async def get_audit_logs(
    limit: int = 50,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador"]))
):
    try:
        stmt = select(AuditLog).order_by(AuditLog.timestamp.desc()).limit(limit)
        result = await db.execute(stmt)
        logs = result.scalars().all()
        return [
            {
                "id": l.id,
                "user_id": l.user_id,
                "username": l.username,
                "action": l.action,
                "timestamp": l.timestamp.isoformat() if l.timestamp else None
            }
            for l in logs
        ]
    except Exception as e:
        import traceback
        traceback.print_exc()
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/holidays", response_model=List[HolidayResponse])
async def get_holidays(db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_active_user)):
    if not current_user.is_admin:
        raise HTTPException(status_code=403, detail="Not authorized")
    try:
        stmt = select(Holiday).where(Holiday.company_id == current_user.company_id)
        result = await db.execute(stmt)
        return result.scalars().all()
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/holidays", response_model=HolidayResponse)
async def create_holiday(holiday: HolidayCreate, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_active_user)):
    if not current_user.is_admin:
        raise HTTPException(status_code=403, detail="Not authorized")
    try:
        db_holiday = Holiday(
            company_id=current_user.company_id,
            date=holiday.date,
            name=holiday.name
        )
        db.add(db_holiday)
        await db.commit()
        await db.refresh(db_holiday)
        return db_holiday
    except Exception as e:
        await db.rollback()
        raise HTTPException(status_code=500, detail=str(e))

@router.delete("/holidays/{holiday_id}")
async def delete_holiday(holiday_id: int, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_active_user)):
    if not current_user.is_admin:
        raise HTTPException(status_code=403, detail="Not authorized")
    try:
        stmt = select(Holiday).where(Holiday.id == holiday_id, Holiday.company_id == current_user.company_id)
        result = await db.execute(stmt)
        holiday = result.scalar_one_or_none()
        if not holiday:
            raise HTTPException(status_code=404, detail="Holiday not found")
        await db.delete(holiday)
        await db.commit()
        return {"ok": True}
    except HTTPException:
        raise
    except Exception as e:
        await db.rollback()
        raise HTTPException(status_code=500, detail=str(e))
