import 'package:flutter/material.dart'; import '../../core/app_colors.dart'; import '../../data/celaya_colonias.dart'; import '../../database/db_helper.dart'; import '../../models/models.dart'; class CreateRouteScreen extends StatefulWidget { final RouteDefinitionModel? editing; const CreateRouteScreen({super.key, this.editing}); @override State createState() => _CreateRouteScreenState(); } class _CreateRouteScreenState extends State { final _nombreCtrl = TextEditingController(); final _routeIdCtrl = TextEditingController(); String _turno = 'MATUTINO'; String _horaInicio = '06:00'; String _horaFin = '08:00'; List _diasSeleccionados = []; List _coloniasSeleccionadas = []; String _searchColonia = ''; bool _loading = false; static const _diasGrupoA = ['LUNES', 'MIERCOLES', 'VIERNES']; static const _diasGrupoB = ['MARTES', 'JUEVES', 'SABADO']; @override void initState() { super.initState(); if (widget.editing != null) { final e = widget.editing!; _nombreCtrl.text = e.nombre; _routeIdCtrl.text = e.routeId; _turno = e.turno; _horaInicio = e.horaInicio; _horaFin = e.horaFin; _diasSeleccionados = List.from(e.dias); _coloniasSeleccionadas = List.from(e.colonias); } } List get _filteredColonias => _searchColonia.isEmpty ? celayaColonias : celayaColonias.where((c) => c.toLowerCase().contains(_searchColonia.toLowerCase())).toList(); Future _guardar() async { if (_nombreCtrl.text.trim().isEmpty) { _snack('Ingresa un nombre para la ruta', isError: true); return; } if (_routeIdCtrl.text.trim().isEmpty) { _snack('Ingresa el ID de la ruta (ej. RUTA-16)', isError: true); return; } if (_diasSeleccionados.isEmpty) { _snack('Selecciona al menos un día', isError: true); return; } if (_coloniasSeleccionadas.isEmpty) { _snack('Selecciona al menos una colonia', isError: true); return; } setState(() => _loading = true); final route = RouteDefinitionModel( id: widget.editing?.id, routeId: _routeIdCtrl.text.trim().toUpperCase(), nombre: _nombreCtrl.text.trim(), dias: _diasSeleccionados, horaInicio: _horaInicio, horaFin: _horaFin, turno: _turno, colonias: _coloniasSeleccionadas, ); await DbHelper.insertRouteDefinition(route); if (!mounted) return; setState(() => _loading = false); _snack('Ruta guardada correctamente'); Navigator.pop(context, true); } void _snack(String msg, {bool isError = false}) => ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text(msg), backgroundColor: isError ? AppColors.rojoError : AppColors.verdeExito)); Future _pickTime(String current) async { final parts = current.split(':'); return showTimePicker( context: context, initialTime: TimeOfDay(hour: int.parse(parts[0]), minute: int.parse(parts[1])), ); } String _timeLabel(TimeOfDay t) => '${t.hour.toString().padLeft(2,'0')}:${t.minute.toString().padLeft(2,'0')}'; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.grisFondo, appBar: AppBar( backgroundColor: AppColors.guindaPrimary, foregroundColor: Colors.white, title: Text(widget.editing != null ? 'Editar Ruta' : 'Nueva Ruta'), bottom: PreferredSize(preferredSize: const Size.fromHeight(4), child: Container(height: 4, color: AppColors.dorado)), ), body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ // Info básica _section('Información de la ruta'), _field(_routeIdCtrl, 'ID de Ruta (ej. RUTA-16)', Icons.tag), const SizedBox(height: 12), _field(_nombreCtrl, 'Nombre descriptivo', Icons.route), const SizedBox(height: 16), // Turno _section('Turno de operación'), Row(children: ['MATUTINO','VESPERTINO','NOCTURNO'].map((t) => Expanded(child: RadioListTile(dense: true, value: t, groupValue: _turno, title: Text(_turnoLabel(t), style: const TextStyle(fontSize: 12)), activeColor: AppColors.guindaPrimary, onChanged: (v) => setState(() => _turno = v!))) ).toList()), const SizedBox(height: 8), // Horario _section('Horario de servicio'), Row(children: [ Expanded(child: _timeButton('Hora inicio', _horaInicio, () async { final t = await _pickTime(_horaInicio); if (t != null) setState(() => _horaInicio = _timeLabel(t)); })), const SizedBox(width: 12), Expanded(child: _timeButton('Hora fin', _horaFin, () async { final t = await _pickTime(_horaFin); if (t != null) setState(() => _horaFin = _timeLabel(t)); })), ]), const SizedBox(height: 16), // Días _section('Días de operación'), Container(padding: const EdgeInsets.all(10), decoration: BoxDecoration(color: Colors.blue.shade50, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.blue.shade200)), child: const Text( ' Selecciona Grupo A (L/M/V) o Grupo B (M/J/S), o días individuales.', style: TextStyle(fontSize: 12, color: AppColors.azulInfo)), ), const SizedBox(height: 8), Row(children: [ Expanded(child: OutlinedButton( onPressed: () => setState(() => _diasSeleccionados = List.from(_diasGrupoA)), style: OutlinedButton.styleFrom( foregroundColor: AppColors.guindaPrimary, side: const BorderSide(color: AppColors.guindaPrimary)), child: const Text('Grupo A\nL/M/V', textAlign: TextAlign.center, style: TextStyle(fontSize: 11)))), const SizedBox(width: 8), Expanded(child: OutlinedButton( onPressed: () => setState(() => _diasSeleccionados = List.from(_diasGrupoB)), style: OutlinedButton.styleFrom( foregroundColor: AppColors.guindaPrimary, side: const BorderSide(color: AppColors.guindaPrimary)), child: const Text('Grupo B\nM/J/S', textAlign: TextAlign.center, style: TextStyle(fontSize: 11)))), ]), const SizedBox(height: 8), Wrap(spacing: 6, runSpacing: 6, children: AppDias.todos.map((dia) { final sel = _diasSeleccionados.contains(dia); return FilterChip( label: Text(AppDias.label(dia), style: TextStyle(fontSize: 11, color: sel ? Colors.white : AppColors.negroTexto)), selected: sel, selectedColor: AppColors.guindaPrimary, checkmarkColor: Colors.white, onSelected: (v) => setState(() { if (v) _diasSeleccionados.add(dia); else _diasSeleccionados.remove(dia); }), ); }).toList()), const SizedBox(height: 16), // Colonias _section('Colonias que cubre (${_coloniasSeleccionadas.length} seleccionadas)'), TextField( onChanged: (v) => setState(() => _searchColonia = v), decoration: const InputDecoration( hintText: 'Buscar colonia de Celaya...', prefixIcon: Icon(Icons.search), border: OutlineInputBorder(), filled: true, fillColor: Colors.white, isDense: true), ), const SizedBox(height: 8), Container(height: 220, decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.grey.shade300)), child: ListView.builder( itemCount: _filteredColonias.length, itemBuilder: (_, i) { final c = _filteredColonias[i]; final sel = _coloniasSeleccionadas.contains(c); return CheckboxListTile(dense: true, title: Text(c, style: const TextStyle(fontSize: 12)), value: sel, activeColor: AppColors.guindaPrimary, controlAffinity: ListTileControlAffinity.leading, onChanged: (v) => setState(() { if (v == true) _coloniasSeleccionadas.add(c); else _coloniasSeleccionadas.remove(c); }), ); }, ), ), if (_coloniasSeleccionadas.isNotEmpty) ...[ const SizedBox(height: 8), Wrap(spacing: 4, runSpacing: 4, children: _coloniasSeleccionadas.map((c) => Chip(label: Text(c, style: const TextStyle(fontSize: 10)), backgroundColor: AppColors.guindaPrimary.withOpacity(0.1), deleteIconColor: AppColors.guindaPrimary, onDeleted: () => setState(() => _coloniasSeleccionadas.remove(c)))).toList()), ], const SizedBox(height: 24), SizedBox(width: double.infinity, height: 50, child: ElevatedButton.icon( onPressed: _loading ? null : _guardar, style: ElevatedButton.styleFrom( backgroundColor: AppColors.guindaPrimary, foregroundColor: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))), icon: _loading ? const SizedBox(width: 18, height: 18, child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2)) : const Icon(Icons.save), label: const Text('GUARDAR RUTA', style: TextStyle(fontWeight: FontWeight.bold)))), const SizedBox(height: 30), ]), ), ); } Widget _section(String title) => Padding( padding: const EdgeInsets.only(bottom: 8), child: Text(title, style: const TextStyle(fontWeight: FontWeight.bold, color: AppColors.guindaPrimary, fontSize: 15))); Widget _field(TextEditingController ctrl, String label, IconData icon) => TextField(controller: ctrl, decoration: InputDecoration(labelText: label, prefixIcon: Icon(icon, color: AppColors.guindaPrimary), border: const OutlineInputBorder(), filled: true, fillColor: Colors.white)); Widget _timeButton(String label, String value, VoidCallback onTap) => InkWell(onTap: onTap, child: Container(padding: const EdgeInsets.all(12), decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.grey.shade400)), child: Row(children: [ const Icon(Icons.access_time, color: AppColors.guindaPrimary, size: 18), const SizedBox(width: 8), Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: const TextStyle(fontSize: 10, color: AppColors.grisTexto)), Text(value, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16)), ]), ]))); String _turnoLabel(String t) => t == 'MATUTINO' ? 'Matutino' : t == 'VESPERTINO' ? 'Vespertino' : 'Nocturno'; @override void dispose() { _nombreCtrl.dispose(); _routeIdCtrl.dispose(); super.dispose(); } }