import 'package:intl/intl.dart';
import 'package:excel/excel.dart';
import 'package:nfc_google_sheet/database/database_helper.dart';
import 'package:nfc_google_sheet/model/attendance.dart';

enum AttendanceResult { success, alreadyScanned, wrongPromotion }

class AttendanceDao {
  static final AttendanceDao instance = AttendanceDao._();
  AttendanceDao._();

  Future<int> insert(Attendance attendance) async {
    final db = await DatabaseHelper.instance.db;
    return await db.insert('attendance', attendance.toMap());
  }

  Future<bool> hasAttendance(String studentId, String subject, String date) async {
    final db = await DatabaseHelper.instance.db;
    final results = await db.query(
      'attendance',
      where: 'studentId = ? AND subject = ? AND date = ?',
      whereArgs: [studentId, subject, date],
    );
    return results.isNotEmpty;
  }

  Future<List<Map<String, dynamic>>> queryWithStudents() async {
    final db = await DatabaseHelper.instance.db;
    return await db.rawQuery('''
      SELECT a.id, a.promotion, a.subject, a.date, a.studentId,
             s.studentId as studentNumber, s.firstName, s.name
      FROM ATTENDANCE a
      LEFT JOIN STUDENT s ON a.studentId = s.cardId
      ORDER BY a.date DESC, a.subject
    ''');
  }

  Future<List<String>> getDistinctPromotions() async {
    final db = await DatabaseHelper.instance.db;
    final results = await db.rawQuery('SELECT DISTINCT promotion FROM ATTENDANCE ORDER BY promotion');
    return results.map((r) => r['promotion'] as String).toList();
  }

  Future<List<String>> getSubjectsByPromotion(String promotion) async {
    final db = await DatabaseHelper.instance.db;
    final results = await db.rawQuery(
      'SELECT DISTINCT subject FROM ATTENDANCE WHERE promotion = ? ORDER BY subject',
      [promotion],
    );
    return results.map((r) => r['subject'] as String).toList();
  }

  Future<List<String>> getDatesByPromotionAndSubject(String promotion, String subject) async {
    final db = await DatabaseHelper.instance.db;
    final results = await db.rawQuery(
      'SELECT DISTINCT date FROM ATTENDANCE WHERE promotion = ? AND subject = ? ORDER BY date DESC',
      [promotion, subject],
    );
    return results.map((r) => r['date'] as String).toList();
  }

  Future<List<Map<String, dynamic>>> queryFiltered(String promotion, String subject, String date) async {
    final db = await DatabaseHelper.instance.db;
    return await db.rawQuery('''
      SELECT a.id, a.promotion, a.subject, a.date, a.studentId,
             s.studentId as studentNumber, s.firstName, s.name
      FROM ATTENDANCE a
      LEFT JOIN STUDENT s ON a.studentId = s.cardId
      WHERE a.promotion = ? AND a.subject = ? AND a.date = ?
      ORDER BY s.name, s.firstName
    ''', [promotion, subject, date]);
  }

  Future<int> delete(String promotion, String subject, String date) async {
    final db = await DatabaseHelper.instance.db;
    return await db.delete(
      'attendance',
      where: 'promotion = ? AND subject = ? AND date = ?',
      whereArgs: [promotion, subject, date],
    );
  }

  static String todayDate() {
    return DateFormat('dd/MM/yyyy').format(DateTime.now());
  }

  Future<AttendanceResult> register(String cardId, String promotion, String expectedPromotion, String subject) async {
    final date = todayDate();

    if (promotion != expectedPromotion) {
      return AttendanceResult.wrongPromotion;
    }

    final alreadyScanned = await hasAttendance(cardId, subject, date);
    if (alreadyScanned) {
      return AttendanceResult.alreadyScanned;
    }

    await insert(Attendance(
      promotion: promotion,
      subject: subject,
      date: date,
      studentId: cardId,
    ));

    return AttendanceResult.success;
  }

  Future<List<int>?> generateExcel(bool includeCardId, {String? promotion, String? subject, String? date}) async {
    final List<Map<String, dynamic>> records;
    if (promotion != null && subject != null && date != null) {
      records = await queryFiltered(promotion, subject, date);
    } else {
      records = await queryWithStudents();
    }
    if (records.isEmpty) return null;

    final excel = Excel.createExcel();
    Sheet sheetObject = excel['Students'];
    excel.delete('Sheet1');

    List<String> headerStrings = ['ID Étudiant', 'Prénom', 'Nom', 'Promotion', 'Matière', 'Date'];
    if (includeCardId) {
      headerStrings.add('ID Carte');
    }

    var headerStyle = CellStyle(
      backgroundColorHex: ExcelColor.yellow300,
      fontFamily: getFontFamily(FontFamily.Calibri),
      bold: true,
      fontColorHex: ExcelColor.deepOrange600,
    );

    for (var i = 0; i < headerStrings.length; i++) {
      var cell = sheetObject.cell(CellIndex.indexByColumnRow(columnIndex: i, rowIndex: 0));
      cell.value = TextCellValue(headerStrings[i]);
      cell.cellStyle = headerStyle;
    }

    for (var record in records) {
      List<String> rowStrings = [
        record['studentNumber'] ?? '',
        record['firstName'] ?? '',
        record['name'] ?? '',
        record['promotion'] ?? '',
        record['subject'] ?? '',
        record['date'] ?? '',
      ];
      if (includeCardId) {
        rowStrings.add(record['studentId'] ?? '');
      }

      List<CellValue> row = rowStrings.map((cell) => TextCellValue(cell)).toList();
      sheetObject.appendRow(row);
    }

    return excel.save();
  }
}
