import 'dart:convert';
import 'package:flutter/services.dart' show rootBundle;
import 'package:googleapis_auth/auth_io.dart' as auth;
import 'package:googleapis/sheets/v4.dart' as sheets;

/// Modèle simple pour alimenter le Dropdown (et savoir quelle ligne mettre à jour).
class StudentItem {
  final int rowIndex; // index réel Google Sheets (1-based)
  final String number; // Col A
  final String firstName; // Col B
  final String lastName; // Col C
  final String? nfc; // Col D
  final String? qr; // Col E

  const StudentItem({
    required this.rowIndex,
    required this.number,
    required this.firstName,
    required this.lastName,
    this.nfc,
    this.qr,
  });

  String get label => '$number - $firstName $lastName';
}

class GoogleSheetsApi {
  static const _spreadsheetId = '1tbWnNSx3J-OAM7rrAxU_YLM97z2zMFtV055nS66Ig3c';
  static const _scopes = [sheets.SheetsApi.spreadsheetsScope];

  Future<auth.AutoRefreshingAuthClient?> _getAuthClient() async {
    try {
      final jsonString = await rootBundle.loadString('assets/credentials.json');
      final credentialsJson = json.decode(jsonString);
      final credentials = auth.ServiceAccountCredentials.fromJson(credentialsJson);
      final client = await auth.clientViaServiceAccount(credentials, _scopes);
      return client;
    } catch (e) {
      // ignore: avoid_print
      print('Erreur lors de l\'authentification : $e');
      return null;
    }
  }

  String _cell(List<dynamic> row, int index) {
    if (index < 0 || index >= row.length) return '';
    final v = row[index];
    return v == null ? '' : v.toString().trim();
  }

  // ---------------------------------------------------------------------------
  // Liste des étudiants pour Dropdown (avec rowIndex compatible update)
  // Colonnes attendues: A=N°, B=Prénom, C=Nom, D=NFC, E=QR
  // ---------------------------------------------------------------------------
  Future<List<StudentItem>> listStudentsForDropdown() async {
    final client = await _getAuthClient();
    if (client == null) return const [];

    final api = sheets.SheetsApi(client);
    const range = 'données etudiants!A:E';

    try {
      final result = await api.spreadsheets.values.get(_spreadsheetId, range);
      final values = result.values;
      if (values == null || values.isEmpty) return const [];

      final items = <StudentItem>[];

      for (int i = 0; i < values.length; i++) {
        if (i == 0) continue; // header

        final row = values[i];

        final number = _cell(row, 0);
        final first = _cell(row, 1);
        final last = _cell(row, 2);
        final nfc = _cell(row, 3);
        final qr = _cell(row, 4);

        if (number.isEmpty && first.isEmpty && last.isEmpty && nfc.isEmpty && qr.isEmpty) {
          continue;
        }

        final rowIndex = i + 1; // i 0-based -> Sheets 1-based

        items.add(
          StudentItem(
            rowIndex: rowIndex,
            number: number,
            firstName: first,
            lastName: last,
            nfc: nfc.isEmpty ? null : nfc,
            qr: qr.isEmpty ? null : qr,
          ),
        );
      }

      items.sort((a, b) => a.number.compareTo(b.number));
      return items;
    } catch (e) {
      // ignore: avoid_print
      print('Erreur listStudentsForDropdown : $e');
      return const [];
    } finally {
      client.close();
    }
  }

  // ---------------------------------------------------------------------------
  // Ajouter une nouvelle ligne
  // ---------------------------------------------------------------------------
  Future<bool> appendData(List<dynamic> rowData) async {
    final client = await _getAuthClient();
    if (client == null) {
      // ignore: avoid_print
      print('Erreur d\'authentification');
      return false;
    }

    final api = sheets.SheetsApi(client);
    const range = 'données etudiants';

    final values = sheets.ValueRange.fromJson({'values': [rowData]});

    try {
      await api.spreadsheets.values.append(
        values,
        _spreadsheetId,
        range,
        valueInputOption: 'RAW',
      );
      // ignore: avoid_print
      print('Données ajoutées !');
      return true;
    } catch (e) {
      // ignore: avoid_print
      print('Erreur lors de l\'ajout des données : $e');
      return false;
    } finally {
      client.close();
    }
  }

  // ---------------------------------------------------------------------------
  // Lire des données (exemple)
  // ---------------------------------------------------------------------------
  Future<List<List<dynamic>>?> readData() async {
    final client = await _getAuthClient();
    if (client == null) {
      // ignore: avoid_print
      print('Erreur d\'authentification');
      return null;
    }

    final api = sheets.SheetsApi(client);
    const range = 'données etudiants!A1:C10';

    try {
      final result = await api.spreadsheets.values.get(_spreadsheetId, range);
      // ignore: avoid_print
      print('Données lues : ${result.values}');
      return result.values;
    } catch (e) {
      // ignore: avoid_print
      print('Erreur lors de la lecture des données : $e');
      return null;
    } finally {
      client.close();
    }
  }

  // ---------------------------------------------------------------------------
  // Lire toutes les valeurs d'une colonne
  // ---------------------------------------------------------------------------
  Future<List<String>> readColumn(String columnName) async {
    final client = await _getAuthClient();
    if (client == null) {
      // ignore: avoid_print
      print('Erreur d\'authentification');
      return [];
    }

    final api = sheets.SheetsApi(client);
    final range = 'données etudiants!$columnName:$columnName';

    try {
      final result = await api.spreadsheets.values.get(_spreadsheetId, range);
      final values = result.values;
      if (values == null) return [];

      final out = <String>[];
      for (final row in values) {
        if (row.isNotEmpty) out.add(row[0].toString());
      }
      return out;
    } catch (e) {
      // ignore: avoid_print
      print('Erreur lors de la lecture de la colonne : $e');
      return [];
    } finally {
      client.close();
    }
  }

  // ---------------------------------------------------------------------------
  // Trouver un nom par l'UID (stocké en Colonne D).
  // IMPORTANT: rowIndex = i + 1 (et non i + 2) car range commence à la ligne 1.
  // ---------------------------------------------------------------------------
  Future<String?> findStudentNameByNfcUid(String uidToCheck) async {
    final client = await _getAuthClient();
    if (client == null) {
      // ignore: avoid_print
      print('Erreur d\'authentification');
      return null;
    }

    final api = sheets.SheetsApi(client);
    const range = 'données etudiants!C:D';

    try {
      final result = await api.spreadsheets.values.get(_spreadsheetId, range);
      final values = result.values;
      if (values == null) {
        // ignore: avoid_print
        print('La feuille est vide ou n\'a pas pu être lue.');
        return null;
      }

      final uidUpper = uidToCheck.toUpperCase().trim();

      for (int i = 0; i < values.length; i++) {
        final row = values[i];
        if (row.length == 2 && row[1] != null) {
          final nfcUidFromSheet = row[1].toString().toUpperCase().trim();
          if (nfcUidFromSheet == uidUpper) {
            await updateLastScan(i + 1, 'F'); // ✅ FIX
            return row[0].toString();
          }
        }
      }

      // ignore: avoid_print
      print('UID non trouvé dans la feuille.');
      return null;
    } catch (e) {
      // ignore: avoid_print
      print('Erreur lors de la recherche de l\'UID : $e');
      return null;
    } finally {
      client.close();
    }
  }

  // ---------------------------------------------------------------------------
  // Récupérer la liste de présence par date (pour le PDF)
  // ---------------------------------------------------------------------------
  Future<List<Map<String, String>>> getPresenceByDate(String date) async {
    final client = await _getAuthClient();
    if (client == null) return [];

    final api = sheets.SheetsApi(client);
    const range = 'données etudiants!A:F';

    try {
      final result = await api.spreadsheets.values.get(_spreadsheetId, range);
      final values = result.values;
      if (values == null) return [];

      final out = <Map<String, String>>[];

      for (int i = 1; i < values.length; i++) {
        final row = values[i];
        final dateAjout = row.length > 5 ? (row[5]?.toString() ?? '') : '';
        if (dateAjout.startsWith(date)) {
          out.add({
            'N° Etudiant': row.length > 0 ? (row[0]?.toString() ?? '') : '',
            'Prénom': row.length > 1 ? (row[1]?.toString() ?? '') : '',
            'Nom': row.length > 2 ? (row[2]?.toString() ?? '') : '',
            'Mac NFC': row.length > 3 ? (row[3]?.toString() ?? '') : '',
            'QR': row.length > 4 ? (row[4]?.toString() ?? '') : '',
            'date_ajout': dateAjout,
          });
        }
      }

      return out;
    } catch (e) {
      // ignore: avoid_print
      print('Erreur getPresenceByDate : $e');
      return [];
    } finally {
      client.close();
    }
  }

  // ---------------------------------------------------------------------------
  // Met à jour la colonne F de la ligne rowIndex en concaténant ";{now}"
  // ---------------------------------------------------------------------------
  Future<void> updateLastScan(int rowIndex, String columnLetter) async {
    final client = await _getAuthClient();
    if (client == null) return;

    final api = sheets.SheetsApi(client);
    final now = DateTime.now().toIso8601String();
    final range = 'données etudiants!$columnLetter$rowIndex';

    try {
      final oldResult = await api.spreadsheets.values.get(_spreadsheetId, range);

      var oldValue = '';
      if (oldResult.values != null &&
          oldResult.values!.isNotEmpty &&
          oldResult.values!.first.isNotEmpty) {
        oldValue = oldResult.values!.first.first.toString();
      }

      oldValue = oldValue.replaceAll('\n', '').replaceAll('\r', '').trim();

      String newValue;
      if (oldValue.isEmpty) {
        newValue = now;
      } else {
        newValue = oldValue.endsWith(now) ? oldValue : '$oldValue;$now';
      }

      final values = sheets.ValueRange.fromJson({'values': [[newValue]]});

      await api.spreadsheets.values.update(
        values,
        _spreadsheetId,
        range,
        valueInputOption: 'RAW',
      );
    } finally {
      client.close();
    }
  }

  // ---------------------------------------------------------------------------
  // Recherche par QR.
  // IMPORTANT: rowIndex = i + 1 (et non i + 2) car range commence à la ligne 1.
  // ---------------------------------------------------------------------------
  Future<String?> findStudentNameByQr(String qrValue) async {
    final client = await _getAuthClient();
    if (client == null) {
      // ignore: avoid_print
      print('Erreur d\'authentification');
      return null;
    }

    final api = sheets.SheetsApi(client);
    const range = 'données etudiants!A:F';

    try {
      final result = await api.spreadsheets.values.get(_spreadsheetId, range);
      final values = result.values;

      if (values == null) {
        // ignore: avoid_print
        print('La feuille est vide ou n\'a pas pu être lue.');
        return null;
      }

      final qrToCheck = qrValue.trim();

      for (int i = 0; i < values.length; i++) {
        final row = values[i];
        if (row.length > 4 && row[4] != null) {
          final qrFromSheet = row[4].toString().trim();
          if (qrFromSheet == qrToCheck) {
            await updateLastScan(i + 1, 'F'); // ✅ FIX
            return row.length > 2 ? row[2].toString() : '';
          }
        }
      }

      // ignore: avoid_print
      print('QR code non trouvé dans la feuille.');
      return null;
    } catch (e) {
      // ignore: avoid_print
      print('Erreur lors de la recherche du QR : $e');
      return null;
    } finally {
      client.close();
    }
  }

  // ---------------------------------------------------------------------------
  // Utilisée par inscription_page.dart
  // ---------------------------------------------------------------------------
  Future<int?> findRowByStudentNumber(String studentNumber) async {
    final client = await _getAuthClient();
    if (client == null) return null;

    final api = sheets.SheetsApi(client);
    const range = 'données etudiants!A:A';

    try {
      final result = await api.spreadsheets.values.get(_spreadsheetId, range);
      final values = result.values;
      if (values == null) return null;

      for (int i = 0; i < values.length; i++) {
        if (values[i].isNotEmpty && values[i][0].toString() == studentNumber) {
          return i + 1; // Sheets 1-based
        }
      }
      return null;
    } catch (e) {
      // ignore: avoid_print
      print('Erreur findRowByStudentNumber : $e');
      return null;
    } finally {
      client.close();
    }
  }

  Future<bool> updateStudentFields({
    required int rowIndex,
    String? nfc,
    String? qr,
  }) async {
    final client = await _getAuthClient();
    if (client == null) return false;

    final api = sheets.SheetsApi(client);

    try {
      final updates = <List<dynamic>>[];

      if (nfc != null && nfc.isNotEmpty) {
        updates.add(['D$rowIndex', nfc]);
      }
      if (qr != null && qr.isNotEmpty) {
        updates.add(['E$rowIndex', qr]);
      }

      for (final u in updates) {
        await api.spreadsheets.values.update(
          sheets.ValueRange.fromJson({'values': [[u[1]]]}),
          _spreadsheetId,
          'données etudiants!${u[0]}',
          valueInputOption: 'USER_ENTERED',
        );
      }

      return true;
    } catch (e) {
      // ignore: avoid_print
      print('Erreur updateStudentFields : $e');
      return false;
    } finally {
      client.close();
    }
  }

  Future<List<Map<String, String>>> getAllPresences() async {
    final client = await _getAuthClient();
    if (client == null) return [];

    final api = sheets.SheetsApi(client);

    try {
      final result = await api.spreadsheets.values.get(
        _spreadsheetId,
        'données etudiants!A:G',
      );

      final values = result.values;
      if (values == null || values.length <= 1) return [];

      final data = <Map<String, String>>[];

      for (int i = 1; i < values.length; i++) {
        final row = values[i];
        data.add({
          'N° Etudiant': row.length > 0 ? row[0].toString() : '',
          'Prénom': row.length > 1 ? row[1].toString() : '',
          'Nom': row.length > 2 ? row[2].toString() : '',
          'Mac NFC': row.length > 3 ? row[3].toString() : '',
          'QR': row.length > 4 ? row[4].toString() : '',
          'date_ajout': row.length > 5 ? row[5].toString() : '',
        });
      }

      return data;
    } catch (e) {
      // ignore: avoid_print
      print('Erreur getAllPresences : $e');
      return [];
    } finally {
      client.close();
    }
  }
}
