from fastapi import APIRouter, Depends, HTTPException, status, Response
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from sqlalchemy import delete
from sqlalchemy.orm import selectinload
from typing import List
import io
import csv
from pydantic import BaseModel, Field

from database import get_db
from models import User, Company, Role, AuditLog
from auth import get_current_active_user, require_roles, get_password_hash
from schemas import CompanyCreate, CompanyResponse, CompanyUpdate, UserResponse, CompanySuperAdminResponse

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

# --- Models para SuperAdmin ---
class AdminUserCreate(BaseModel):
    username: str = Field(..., max_length=50)
    email: str = Field(..., max_length=100)
    password: str
    company_id: int

class AdminPasswordChange(BaseModel):
    new_password: str

# --- Gestión de Empresas ---

@router.get("/companies", response_model=List[CompanySuperAdminResponse])
async def get_companies(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Super Administrador"]))
):
    from sqlalchemy import func
    stmt = select(Company).order_by(Company.id)
    res = await db.execute(stmt)
    companies = res.scalars().all()
    
    result = []
    for c in companies:
        c_dict = {
            "id": c.id,
            "name": c.name,
            "is_active": c.is_active,
            "created_at": c.created_at,
            "log_count": 0,
            "log_size_kb": 0.0
        }
        # Get users for this company
        user_stmt = select(User.id).where(User.company_id == c.id)
        u_res = await db.execute(user_stmt)
        user_ids = u_res.scalars().all()
        
        if user_ids:
            # Count logs
            log_stmt = select(func.count(AuditLog.id)).where(AuditLog.user_id.in_(user_ids))
            l_res = await db.execute(log_stmt)
            log_count = l_res.scalar_one_or_none() or 0
            
            c_dict["log_count"] = log_count
            # Rough estimate: ~256 bytes per log entry
            c_dict["log_size_kb"] = round((log_count * 256) / 1024, 2)
            
        result.append(c_dict)
        
    return result

@router.put("/companies/{company_id}")
async def update_company(
    company_id: int,
    company_data: CompanyUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Super Administrador"]))
):
    db_company = await db.get(Company, company_id)
    if not db_company:
        raise HTTPException(status_code=404, detail="Empresa no encontrada")
    
    if company_data.name is not None:
        # Verificar que no exista otra con el mismo nombre
        stmt = select(Company).where(Company.name == company_data.name, Company.id != company_id)
        res = await db.execute(stmt)
        if res.scalar_one_or_none():
            raise HTTPException(status_code=400, detail="Ya existe otra empresa con ese nombre")
        db_company.name = company_data.name
    
    if company_data.is_active is not None:
        db_company.is_active = company_data.is_active
        
    await db.commit()
    return {"message": "Empresa actualizada exitosamente"}

@router.get("/companies/{company_id}/logs/download")
async def download_company_logs(
    company_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Super Administrador"]))
):
    db_company = await db.get(Company, company_id)
    if not db_company:
        raise HTTPException(status_code=404, detail="Empresa no encontrada")
        
    stmt_users = select(User.id).where(User.company_id == company_id)
    res_users = await db.execute(stmt_users)
    user_ids = [row for row in res_users.scalars().all()]
    
    if not user_ids:
        raise HTTPException(status_code=404, detail="No hay logs para descargar")
        
    stmt_logs = select(AuditLog).where(AuditLog.user_id.in_(user_ids)).order_by(AuditLog.timestamp.desc())
    res_logs = await db.execute(stmt_logs)
    logs = res_logs.scalars().all()
    
    output = io.StringIO()
    writer = csv.writer(output, delimiter=',', quoting=csv.QUOTE_MINIMAL)
    writer.writerow(['ID', 'User ID', 'Username', 'Accion', 'IP', 'Fecha'])
    for log in logs:
        writer.writerow([
            log.id, 
            log.user_id, 
            log.username, 
            log.action, 
            log.ip_address or "", 
            log.timestamp.isoformat() if log.timestamp else ""
        ])
        
    csv_content = output.getvalue()
    output.close()
    
    headers = {
        'Content-Disposition': f'attachment; filename="logs_empresa_{company_id}.csv"'
    }
    return Response(content=csv_content, media_type="text/csv", headers=headers)

@router.delete("/companies/{company_id}/logs")
async def purge_company_logs(
    company_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Super Administrador"]))
):
    # Verify company exists
    db_company = await db.get(Company, company_id)
    if not db_company:
        raise HTTPException(status_code=404, detail="Empresa no encontrada")
    
    # Get all user IDs for this company
    stmt_users = select(User.id).where(User.company_id == company_id)
    res_users = await db.execute(stmt_users)
    user_ids = [row for row in res_users.scalars().all()]
    
    if not user_ids:
        return {"message": "No hay usuarios ni logs asociados a esta empresa"}
        
    # Delete logs
    stmt_delete = delete(AuditLog).where(AuditLog.user_id.in_(user_ids))
    await db.execute(stmt_delete)
    
    # Optional: Log the purge action itself by the superadmin
    audit = AuditLog(
        user_id=current_user.id,
        username=current_user.username,
        action=f"Purgó los logs de la empresa '{db_company.name}' (ID: {company_id})"
    )
    db.add(audit)
    
    await db.commit()
    return {"message": f"Logs purgados exitosamente para la empresa '{db_company.name}'"}

@router.post("/companies", response_model=CompanyResponse)
async def create_company(
    company: CompanyCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Super Administrador"]))
):
    stmt = select(Company).where(Company.name == company.name)
    res = await db.execute(stmt)
    if res.scalar_one_or_none():
        raise HTTPException(status_code=400, detail="Company name already exists")
        
    db_comp = Company(name=company.name, is_active=company.is_active)
    db.add(db_comp)
    await db.commit()
    await db.refresh(db_comp)
    return db_comp

@router.post("/companies/{company_id}/toggle", response_model=CompanyResponse)
async def toggle_company(
    company_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Super Administrador"]))
):
    stmt = select(Company).where(Company.id == company_id)
    res = await db.execute(stmt)
    company = res.scalar_one_or_none()
    
    if not company:
        raise HTTPException(status_code=404, detail="Company not found")
        
    company.is_active = not company.is_active
    await db.commit()
    await db.refresh(company)
    return company

@router.delete("/companies/{company_id}")
async def delete_company(
    company_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Super Administrador"]))
):
    from sqlalchemy import delete
    stmt = delete(Company).where(Company.id == company_id)
    await db.execute(stmt)
    await db.commit()
    return {"message": "Company deleted"}

# --- Gestión de Usuarios Administradores ---

@router.get("/users", response_model=List[UserResponse])
async def get_admin_users(
    company_id: int = None,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Super Administrador"]))
):
    stmt = select(User).options(selectinload(User.roles), selectinload(User.company), selectinload(User.viewable_projects)).join(User.roles).where(Role.name == "Administrador")
    if company_id:
        stmt = stmt.where(User.company_id == company_id)
        
    res = await db.execute(stmt)
    return res.scalars().all()

@router.post("/users", response_model=UserResponse)
async def create_admin_user(
    user: AdminUserCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Super Administrador"]))
):
    stmt = select(User).where(User.username == user.username)
    res = await db.execute(stmt)
    if res.scalar_one_or_none():
        raise HTTPException(status_code=400, detail="Username already exists")
        
    stmt_comp = select(Company).where(Company.id == user.company_id)
    res_comp = await db.execute(stmt_comp)
    if not res_comp.scalar_one_or_none():
        raise HTTPException(status_code=404, detail="Company not found")
        
    stmt_role = select(Role).where(Role.name == "Administrador")
    res_role = await db.execute(stmt_role)
    role = res_role.scalar_one_or_none()
    if not role:
        raise HTTPException(status_code=500, detail="Administrador role not found in DB")
        
    hashed_password = get_password_hash(user.password)
    db_user = User(
        username=user.username,
        email=user.email,
        hashed_password=hashed_password,
        company_id=user.company_id,
        is_active=True
    )
    db.add(db_user)
    await db.commit()
    await db.refresh(db_user)
    
    db_user.roles.append(role)
    await db.commit()
    
    stmt_reload = select(User).options(selectinload(User.roles), selectinload(User.company), 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}/password")
async def change_admin_password(
    user_id: int,
    data: AdminPasswordChange,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Super Administrador"]))
):
    stmt = select(User).options(selectinload(User.roles)).where(User.id == user_id)
    res = await db.execute(stmt)
    target_user = res.scalar_one_or_none()
    
    if not target_user:
        raise HTTPException(status_code=404, detail="User not found")
        
    if not any(r.name == "Administrador" for r in target_user.roles):
        raise HTTPException(status_code=400, detail="Can only change passwords for Administrador users")
        
    target_user.hashed_password = get_password_hash(data.new_password)
    await db.commit()
    return {"message": "Password updated successfully"}
