import 'package:sqflite/sqflite.dart'; import 'package:path/path.dart'; import '../models/models.dart'; import '../models/route_model.dart'; class DbHelper { static Database? _db; static Future get database async { _db ??= await _initDb(); return _db!; } static Future _initDb() async { final path = join(await getDatabasesPath(), 'celaya_v2.db'); return openDatabase(path, version: 1, onCreate: _onCreate); } static Future _onCreate(Database db, int v) async { await db.execute('''CREATE TABLE users( id INTEGER PRIMARY KEY AUTOINCREMENT, nombre TEXT NOT NULL, email TEXT UNIQUE NOT NULL, password TEXT NOT NULL, rol TEXT NOT NULL)'''); await db.execute('''CREATE TABLE domicilios( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, calle TEXT NOT NULL, colonia TEXT NOT NULL, route_id TEXT NOT NULL, horario_estimado TEXT NOT NULL, is_primary INTEGER DEFAULT 1)'''); await db.execute('''CREATE TABLE asignaciones( id INTEGER PRIMARY KEY AUTOINCREMENT, conductor_id INTEGER NOT NULL, route_id TEXT NOT NULL, dia_semana TEXT NOT NULL, turno TEXT NOT NULL)'''); await db.execute('''CREATE TABLE route_status( route_id TEXT PRIMARY KEY, status TEXT NOT NULL, mensaje TEXT, updated_at TEXT)'''); await db.execute('''CREATE TABLE alertas( id INTEGER PRIMARY KEY AUTOINCREMENT, tipo TEXT NOT NULL, route_id TEXT NOT NULL, mensaje TEXT NOT NULL, fecha TEXT NOT NULL, resuelta INTEGER DEFAULT 0)'''); await db.execute('''CREATE TABLE reportes( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, tipo TEXT NOT NULL, descripcion TEXT NOT NULL, colonia TEXT NOT NULL, route_id TEXT, fecha TEXT NOT NULL, estado TEXT DEFAULT 'PENDIENTE', calificacion INTEGER DEFAULT 5)'''); // Seed: admin y conductor demo await db.insert('users', {'nombre':'Administrador','email':'admin@celaya.gob.mx', 'password':'admin123','rol':'ADMINISTRADOR'}); await db.insert('users', {'nombre':'Juan Conductor','email':'conductor@celaya.gob.mx', 'password':'conductor123','rol':'CONDUCTOR'}); } // ── USERS ────────────────────────────────────────────────────────────── static Future insertUser(UserModel u) async => (await database).insert('users', u.toMap(), conflictAlgorithm: ConflictAlgorithm.abort); static Future getUserByEmail(String email) async { final res = await (await database).query('users', where:'email=?', whereArgs:[email]); return res.isEmpty ? null : UserModel.fromMap(res.first); } static Future getUserById(int id) async { final res = await (await database).query('users', where:'id=?', whereArgs:[id]); return res.isEmpty ? null : UserModel.fromMap(res.first); } static Future> getUsersByRol(String rol) async { final res = await (await database).query('users', where:'rol=?', whereArgs:[rol]); return res.map((m) => UserModel.fromMap(m)).toList(); } // ── DOMICILIOS ───────────────────────────────────────────────────────── static Future insertDomicilio(DomicilioModel d) async => (await database).insert('domicilios', d.toMap()); static Future getPrimaryDomicilio(int userId) async { final res = await (await database).query('domicilios', where:'user_id=? AND is_primary=1', whereArgs:[userId]); return res.isEmpty ? null : DomicilioModel.fromMap(res.first); } // ── ASIGNACIONES ─────────────────────────────────────────────────────── static Future upsertAsignacion(AssignmentModel a) async { final db = await database; final ex = await db.query('asignaciones', where:'conductor_id=? AND dia_semana=?', whereArgs:[a.conductorId, a.diaSemana]); if (ex.isEmpty) { await db.insert('asignaciones', a.toMap()); } else { await db.update('asignaciones', {'route_id':a.routeId,'turno':a.turno}, where:'conductor_id=? AND dia_semana=?', whereArgs:[a.conductorId, a.diaSemana]); } } static Future> getAsignacionesByConductor(int conductorId) async { final res = await (await database).query('asignaciones', where:'conductor_id=?', whereArgs:[conductorId]); return res.map((m) => AssignmentModel.fromMap(m)).toList(); } static Future> getAllAsignaciones() async { final res = await (await database).query('asignaciones'); return res.map((m) => AssignmentModel.fromMap(m)).toList(); } // ── ROUTE STATUS ─────────────────────────────────────────────────────── static Future upsertRouteStatus(RouteStatusModel s) async { final db = await database; await db.insert('route_status', s.toMap(), conflictAlgorithm: ConflictAlgorithm.replace); } static Future getRouteStatus(String routeId) async { final res = await (await database).query('route_status', where:'route_id=?', whereArgs:[routeId]); return res.isEmpty ? null : RouteStatusModel.fromMap(res.first); } static Future> getAllRouteStatuses() async { final res = await (await database).query('route_status'); return res.map((m) => RouteStatusModel.fromMap(m)).toList(); } // ── ALERTAS ──────────────────────────────────────────────────────────── static Future insertAlerta(AlertaModel a) async => (await database).insert('alertas', a.toMap()); static Future> getAlertas({bool soloNoResueltas = false}) async { final db = await database; final res = soloNoResueltas ? await db.query('alertas', where:'resuelta=0', orderBy:'fecha DESC') : await db.query('alertas', orderBy:'fecha DESC'); return res.map((m) => AlertaModel.fromMap(m)).toList(); } static Future resolverAlerta(int id) async => (await database).update('alertas', {'resuelta':1}, where:'id=?', whereArgs:[id]); // ── REPORTES ─────────────────────────────────────────────────────────── static Future insertReporte(ReporteModel r) async => (await database).insert('reportes', r.toMap()); static Future> getReportesByUser(int userId) async { final res = await (await database).query('reportes', where:'user_id=?', whereArgs:[userId], orderBy:'fecha DESC'); return res.map((m) => ReporteModel.fromMap(m)).toList(); } static Future> getAllReportes() async { final res = await (await database).query('reportes', orderBy:'fecha DESC'); return res.map((m) => ReporteModel.fromMap(m)).toList(); } static Future updateReporteEstado(int id, String estado) async => (await database).update('reportes', {'estado':estado}, where:'id=?', whereArgs:[id]); // ── REPORTES CON INFO DE USUARIO ────────────────────────────────────── static Future>> getReportesConUsuario() async { final db = await database; return db.rawQuery(''' SELECT r.*, u.nombre as user_nombre, u.email as user_email FROM reportes r LEFT JOIN users u ON r.user_id = u.id ORDER BY r.fecha DESC '''); } // ── INCIDENTES CONDUCTOR ─────────────────────────────────────────────── static Future> getIncidentesConductor() async { final res = await (await database).query('alertas', where: "tipo LIKE 'INCIDENTE_%'", orderBy: 'fecha DESC'); return res.map((m) => AlertaModel.fromMap(m)).toList(); } // ── DOMICILIOS POR RUTA ──────────────────────────────────────────────── static Future> getDomiciliosByRoute(String routeId) async { final res = await (await database).query('domicilios', where: 'route_id = ?', whereArgs: [routeId]); return res.map((m) => DomicilioModel.fromMap(m)).toList(); } }