import 'package:flutter/material.dart'; import '../../core/app_colors.dart'; import '../../database/db_helper.dart'; class ManageConductorsScreen extends StatefulWidget { const ManageConductorsScreen({super.key}); @override State createState() => _ManageConductorsScreenState(); } class _ManageConductorsScreenState extends State { List> _conductores = []; bool _loading = true; @override void initState() { super.initState(); _load(); } Future _load() async { final c = await DbHelper.getConductoresConMeta(); if (mounted) setState(() { _conductores = c; _loading = false; }); } Future _showFormDialog({Map? existing}) async { final nombreCtrl = TextEditingController(text: existing?['nombre'] ?? ''); final emailCtrl = TextEditingController(text: existing?['email'] ?? ''); final passCtrl = TextEditingController(); final notasCtrl = TextEditingController(text: existing?['notas'] ?? ''); bool activo = (existing?['activo'] as int? ?? 1) == 1; bool obscure = true; await showDialog(context: context, builder: (ctx) => StatefulBuilder( builder: (ctx, setSt) => AlertDialog( title: Text(existing == null ? 'Nuevo Conductor' : 'Editar Conductor'), content: SingleChildScrollView(child: Column(mainAxisSize: MainAxisSize.min, children: [ TextField(controller: nombreCtrl, decoration: const InputDecoration(labelText: 'Nombre completo', prefixIcon: Icon(Icons.person_outline), border: OutlineInputBorder())), const SizedBox(height: 10), TextField(controller: emailCtrl, keyboardType: TextInputType.emailAddress, decoration: const InputDecoration(labelText: 'Correo electronico', prefixIcon: Icon(Icons.email_outlined), border: OutlineInputBorder())), const SizedBox(height: 10), if (existing == null) TextField(controller: passCtrl, obscureText: obscure, decoration: InputDecoration(labelText: 'Contrasena', prefixIcon: const Icon(Icons.lock_outline), border: const OutlineInputBorder(), suffixIcon: IconButton(icon: Icon(obscure ? Icons.visibility_off : Icons.visibility), onPressed: () => setSt(() => obscure = !obscure)))), if (existing == null) const SizedBox(height: 10), TextField(controller: notasCtrl, maxLines: 2, decoration: const InputDecoration(labelText: 'Notas internas (opcional)', border: OutlineInputBorder())), const SizedBox(height: 10), if (existing != null) SwitchListTile(value: activo, dense: true, title: Text(activo ? 'Conductor Activo' : 'Conductor Inactivo', style: TextStyle(color: activo ? AppColors.guindaPrimary : AppColors.rojoError, fontWeight: FontWeight.bold)), activeColor: AppColors.guindaPrimary, onChanged: (v) => setSt(() => activo = v)), ])), actions: [ TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('Cancelar')), ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: AppColors.guindaPrimary, foregroundColor: Colors.white), onPressed: () async { if (nombreCtrl.text.trim().isEmpty) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar( content: Text('Ingresa el nombre del conductor'), backgroundColor: AppColors.rojoError)); return; } if (emailCtrl.text.trim().isEmpty) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar( content: Text('Ingresa el correo electronico'), backgroundColor: AppColors.rojoError)); return; } try { if (existing == null) { if (passCtrl.text.length < 6) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar( content: Text('La contrasena debe tener al menos 6 caracteres'), backgroundColor: AppColors.rojoError)); return; } await DbHelper.insertConductor( nombreCtrl.text.trim(), emailCtrl.text.trim().toLowerCase(), passCtrl.text); if (ctx.mounted) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar( content: Text('Conductor creado correctamente'), backgroundColor: AppColors.verdeExito)); } } else { await DbHelper.updateConductor(existing['id'], nombreCtrl.text.trim(), emailCtrl.text.trim().toLowerCase()); await DbHelper.updateConductorMeta( existing['id'], activo, notasCtrl.text.trim()); } if (ctx.mounted) Navigator.pop(ctx); await _load(); } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text(e.toString().contains('UNIQUE') ? 'Ese correo ya está registrado' : 'Error: ${e.toString()}'), backgroundColor: AppColors.rojoError)); } } }, child: Text(existing == null ? 'Crear' : 'Guardar')), ]))); } @override Widget build(BuildContext context) => Scaffold( backgroundColor: AppColors.grisFondo, appBar: AppBar( backgroundColor: AppColors.guindaPrimary, foregroundColor: Colors.white, title: Text('Conductores (${_conductores.length})'), bottom: PreferredSize(preferredSize: const Size.fromHeight(4), child: Container(height: 4, color: AppColors.dorado)), actions: [ IconButton(icon: const Icon(Icons.refresh), onPressed: _load), IconButton(icon: const Icon(Icons.add_circle_outline), tooltip: 'Nuevo conductor', onPressed: () => _showFormDialog()), ], ), body: _loading ? const Center(child: CircularProgressIndicator()) : _conductores.isEmpty ? Center(child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.person_off, color: AppColors.grisTexto, size: 48), const SizedBox(height: 12), const Text('Sin conductores registrados', style: TextStyle(color: AppColors.grisTexto)), const SizedBox(height: 16), ElevatedButton.icon( style: ElevatedButton.styleFrom(backgroundColor: AppColors.guindaPrimary, foregroundColor: Colors.white), onPressed: () => _showFormDialog(), icon: const Icon(Icons.add), label: const Text('Agregar primer conductor')), ])) : ListView.builder( padding: const EdgeInsets.all(12), itemCount: _conductores.length, itemBuilder: (_, i) { final c = _conductores[i]; final activo = (c['activo'] as int? ?? 1) == 1; final incidentes = c['total_incidentes'] as int? ?? 0; return Card( margin: const EdgeInsets.only(bottom: 10), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10), side: BorderSide(color: activo ? AppColors.guindaPrimary.withOpacity(0.3) : AppColors.rojoError.withOpacity(0.3))), child: Padding(padding: const EdgeInsets.all(14), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row(children: [ CircleAvatar(radius: 22, backgroundColor: activo ? AppColors.guindaPrimary.withOpacity(0.15) : Colors.grey.shade200, child: Icon(Icons.person, color: activo ? AppColors.guindaPrimary : AppColors.grisTexto, size: 24)), const SizedBox(width: 12), Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(c['nombre'] ?? '', style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 14)), Text(c['email'] ?? '', style: const TextStyle( color: AppColors.grisTexto, fontSize: 12)), ])), Container(padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: activo ? AppColors.guindaPrimary.withOpacity(0.1) : AppColors.rojoError.withOpacity(0.1), borderRadius: BorderRadius.circular(10)), child: Text(activo ? 'Activo' : 'Inactivo', style: TextStyle(fontSize: 11, fontWeight: FontWeight.bold, color: activo ? AppColors.guindaPrimary : AppColors.rojoError))), IconButton(icon: const Icon(Icons.edit_outlined, size: 18), onPressed: () => _showFormDialog(existing: c)), ]), if (incidentes > 0 || (c['notas'] as String?)?.isNotEmpty == true) ...[ const Divider(height: 16), if (incidentes > 0) Row(children: [ Icon(Icons.warning_amber, size: 14, color: incidentes > 3 ? AppColors.rojoError : AppColors.naranjaAlerta), const SizedBox(width: 4), Text('$incidentes incidente${incidentes != 1 ? 's' : ''} historico${incidentes != 1 ? 's' : ''}', style: TextStyle(fontSize: 12, color: incidentes > 3 ? AppColors.rojoError : AppColors.naranjaAlerta)), ]), if ((c['notas'] as String?)?.isNotEmpty == true) ...[ const SizedBox(height: 4), Text('Notas: ${c['notas']}', style: const TextStyle(fontSize: 11, color: AppColors.grisTexto, fontStyle: FontStyle.italic)), ], ], ]))); }), ); }