import 'package:flutter/services.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:em2rp/services/qr_code_service.dart';

/// Formats d'étiquettes QR disponibles
enum QRLabelFormat { small, medium, large }

/// Configuration pour la génération de PDF
class PDFGeneratorConfig {
  final double qrCodeSize;
  final int itemsPerPage;
  final bool withProgress;

  const PDFGeneratorConfig({
    required this.qrCodeSize,
    required this.itemsPerPage,
    this.withProgress = false,
  });

  static const small = PDFGeneratorConfig(
    qrCodeSize: 150,
    itemsPerPage: 50,
  );

  // 4 colonnes x 10 lignes = 40 étiquettes
  static const medium = PDFGeneratorConfig(
    qrCodeSize: 150, // Réduit légèrement pour entrer dans 25.4mm de haut
    itemsPerPage: 40,
  );

  // 2 colonnes x 5 lignes = 10 étiquettes
  static const large = PDFGeneratorConfig(
    qrCodeSize: 300,
    itemsPerPage: 10,
  );

  static PDFGeneratorConfig fromFormat(QRLabelFormat format) {
    switch (format) {
      case QRLabelFormat.small:
        return small;
      case QRLabelFormat.medium:
        return medium;
      case QRLabelFormat.large:
        return large;
    }
  }
}

/// Service UNIQUE et optimisé pour la génération de PDFs avec QR codes
class PDFService {
  static Uint8List? _cachedLogoBytes;
  static bool _logoLoadAttempted = false;

  /// Charge le logo en cache une seule fois
  static Future<void> _ensureLogoLoaded() async {
    if (_logoLoadAttempted) return;
    _logoLoadAttempted = true;

    try {
      final logoData = await rootBundle.load('assets/logos/LowQRectangleLogoBlack.png');
      _cachedLogoBytes = logoData.buffer.asUint8List();
    } catch (e) {
      _cachedLogoBytes = Uint8List(0);
    }
  }

  /// Tronque un texte
  static String _truncate(String text, int max) {
    return text.length <= max ? text : '${text.substring(0, max - 3)}...';
  }

  /// Génère un PDF avec QR codes pour n'importe quel type d'objet
  static Future<Uint8List> generatePDF<T>({
    required List<T> items,
    required QRLabelFormat format,
    required String Function(T) getId,
    String Function(T)? getTitle,
    List<String> Function(T)? getDetails,
    Function(int current, int total)? onProgress,
  }) async {
    if (items.isEmpty) {
      throw Exception('La liste d\'items est vide');
    }

    final config = PDFGeneratorConfig.fromFormat(format);
    final pdf = pw.Document();

    // Pré-charger le logo pour formats medium et large
    if (format == QRLabelFormat.medium || format == QRLabelFormat.large) {
      await _ensureLogoLoaded();
    }

    // Générer tous les QR codes en bulk avec progression
    final allQRImages = await QRCodeService.generateBulkQRCodes(
      items.map((item) => getId(item)).toList(),
      size: config.qrCodeSize,
      withLogo: false,
      useCache: true,
      onProgress: onProgress,
    );

    // Générer les pages
    switch (format) {
      case QRLabelFormat.small:
        _addSmallLabels(pdf, items, getId, allQRImages, config);
        break;
      case QRLabelFormat.medium:
        _addMediumLabels(pdf, items, getId, getTitle, allQRImages, config);
        break;
      case QRLabelFormat.large:
        _addLargeLabels(pdf, items, getId, getTitle, getDetails, allQRImages, config);
        break;
    }

    return pdf.save();
  }

  // ========================================================================
  // PETITS LABELS (Original: 2x2 cm approx)
  // ========================================================================
  static void _addSmallLabels<T>(
      pw.Document pdf,
      List<T> items,
      String Function(T) getId,
      List<Uint8List> qrImages,
      PDFGeneratorConfig config,
      ) {
    const qrSize = 56.69; // ~2cm

    for (int pageStart = 0; pageStart < items.length; pageStart += config.itemsPerPage) {
      final pageItems = items.skip(pageStart).take(config.itemsPerPage).toList();
      final pageQRs = qrImages.skip(pageStart).take(config.itemsPerPage).toList();

      pdf.addPage(
        pw.Page(
          pageFormat: PdfPageFormat.a4,
          margin: const pw.EdgeInsets.all(20),
          build: (_) => pw.Wrap(
            spacing: 10,
            runSpacing: 10,
            children: List.generate(pageItems.length, (i) {
              return pw.Container(
                width: qrSize,
                height: qrSize + 20,
                child: pw.Column(
                  mainAxisAlignment: pw.MainAxisAlignment.center,
                  children: [
                    pw.Image(pw.MemoryImage(pageQRs[i])),
                    pw.SizedBox(height: 2),
                    pw.Text(
                      getId(pageItems[i]),
                      style: pw.TextStyle(fontSize: 6, fontWeight: pw.FontWeight.bold),
                      textAlign: pw.TextAlign.center,
                    ),
                  ],
                ),
              );
            }),
          ),
        ),
      );
    }
  }
// ========================================================================
  // LABELS MOYENS (49 x 26 mm | 4 colonnes, 10 lignes)
  // ========================================================================
  static void _addMediumLabels<T>(
      pw.Document pdf,
      List<T> items,
      String Function(T) getId,
      String Function(T)? getTitle,
      List<Uint8List> qrImages,
      PDFGeneratorConfig config,
      ) {
    // 1. Dimensions exactes des étiquettes
    const double labelWidth = 50 * PdfPageFormat.mm;
    const double labelHeight = 26.0 * PdfPageFormat.mm;

    // 2. Calcul du centrage manuel
    // Marge théorique = (210mm - (49*4)) / 2 = 7mm
    // CORRECTION : On enlève 1.5mm pour réduire la marge de gauche (décalage vers la gauche)
    const double horizontalCorrection = PdfPageFormat.mm;

    final double leftMargin = ((PdfPageFormat.a4.width - (labelWidth * 4)) / 2) + horizontalCorrection;

    // Centrage vertical standard
    final double topMargin = (PdfPageFormat.a4.height - (labelHeight * 10)) / 2 -0.75;

    for (int pageStart = 0; pageStart < items.length; pageStart += config.itemsPerPage) {
      final pageItems = items.skip(pageStart).take(config.itemsPerPage).toList();
      final pageQRs = qrImages.skip(pageStart).take(config.itemsPerPage).toList();

      pdf.addPage(
        pw.Page(
          pageFormat: PdfPageFormat.a4,
          // 3. Application des marges calculées (plus de pw.Center)
          margin: pw.EdgeInsets.only(
              left: leftMargin,
              top: topMargin,
              right: 0,
              bottom: 0
          ),
          build: (_) => pw.Wrap(
            spacing: 0,
            runSpacing: 0,
            children: List.generate(pageItems.length, (i) {
              return pw.Container(
                width: labelWidth,
                height: labelHeight,
                padding: const pw.EdgeInsets.all(2),
                child: pw.Row(
                  children: [
                    // QR Code à gauche
                    pw.Container(
                      width: labelHeight - 4,
                      height: labelHeight - 4,
                      child: pw.Image(pw.MemoryImage(pageQRs[i])),
                    ),
                    pw.SizedBox(width: 4),
                    // Texte à droite
                    pw.Expanded(
                      child: pw.Column(
                        mainAxisAlignment: pw.MainAxisAlignment.center,
                        crossAxisAlignment: pw.CrossAxisAlignment.start,
                        children: [
                          // Logo
                          if (_cachedLogoBytes != null && _cachedLogoBytes!.isNotEmpty)
                            pw.Container(
                              height: 12,
                              alignment: pw.Alignment.centerLeft,
                              margin: const pw.EdgeInsets.only(bottom: 2),
                              child: pw.Image(pw.MemoryImage(_cachedLogoBytes!)),
                            ),
                          pw.Text(
                            getId(pageItems[i]),
                            style: pw.TextStyle(fontSize: 7, fontWeight: pw.FontWeight.bold),
                            maxLines: 1,
                          ),
                          if (getTitle != null)
                            pw.Text(
                              _truncate(getTitle(pageItems[i]), 18),
                              style: const pw.TextStyle(fontSize: 6, color: PdfColors.grey700),
                              maxLines: 2,
                              overflow: pw.TextOverflow.clip,
                            ),
                        ],
                      ),
                    ),
                  ],
                ),
              );
            }),
          ),
        ),
      );
    }
  }

  // ========================================================================
  // GRANDS LABELS (105 x 57 mm | 2 colonnes, 5 lignes)
  // ========================================================================
  static void _addLargeLabels<T>(
      pw.Document pdf,
      List<T> items,
      String Function(T) getId,
      String Function(T)? getTitle,
      List<String> Function(T)? getDetails,
      List<Uint8List> qrImages,
      PDFGeneratorConfig config,
      ) {
    // UTILISATION DE LA LARGEUR A4 DIVISÉE PAR 2
    // Cela garantit que 2 colonnes rentrent pile poil (210mm / 2 = 105mm)
    final double labelWidth = PdfPageFormat.a4.width / 2;
    const double labelHeight = 57.0 * PdfPageFormat.mm;
    const int cols = 2;
    const int rows = 5;

    final double totalGridWidth = labelWidth * cols;
    final double totalGridHeight = labelHeight * rows;

    const double innerQrSize = 45.0 * PdfPageFormat.mm;

    for (int pageStart = 0; pageStart < items.length; pageStart += config.itemsPerPage) {
      final pageItems = items.skip(pageStart).take(config.itemsPerPage).toList();
      final pageQRs = qrImages.skip(pageStart).take(config.itemsPerPage).toList();

              pdf.addPage(
        pw.Page(
          pageFormat: PdfPageFormat.a4,
          margin: pw.EdgeInsets.zero,
          build: (_) => pw.Center(
            child: pw.Container(
              width: totalGridWidth,
              height: totalGridHeight,
              child: pw.Wrap(
                spacing: 0, // Très important : 0 espace entre les colonnes
                runSpacing: 0, // 0 espace entre les lignes
                children: List.generate(pageItems.length, (i) {
                  final item = pageItems[i];
                  // Déterminer si c'est la première colonne (indices pairs)
                  final bool isFirstColumn = (i % 2) == 0;
                  // Décalage de 2mm pour la première colonne
                  final double leftPadding = isFirstColumn ? 8.0 : 6.0; // 6 + 2mm

                  return pw.Container(
                    width: labelWidth,
                    height: labelHeight,
                    padding: pw.EdgeInsets.only(
                      left: leftPadding,
                      right: 6,
                      top: 6,
                      bottom: 6,
                    ),
                    // Suppression de la décoration (bordure)
                    child: pw.Row(
                      crossAxisAlignment: pw.CrossAxisAlignment.center,
                      children: [
                        // QR Code
                        pw.Container(
                          width: innerQrSize,
                          height: innerQrSize,
                          child: pw.Image(pw.MemoryImage(pageQRs[i])),
                        ),
                        pw.SizedBox(width: 8),
                        // Détails
                        pw.Expanded(
                          child: pw.Column(
                            crossAxisAlignment: pw.CrossAxisAlignment.start,
                            mainAxisAlignment: pw.MainAxisAlignment.center,
                            children: [
                              // Logo
                              if (_cachedLogoBytes != null && _cachedLogoBytes!.isNotEmpty)
                                pw.Container(
                                  height: 20,
                                  alignment: pw.Alignment.centerLeft,
                                  margin: const pw.EdgeInsets.only(bottom: 4),
                                  child: pw.Image(pw.MemoryImage(_cachedLogoBytes!)),
                                ),
                              // Titre
                              if (getTitle != null) ...[
                                pw.Text(
                                  _truncate(getTitle(item), 40),
                                  style: pw.TextStyle(fontSize: 11, fontWeight: pw.FontWeight.bold),
                                  maxLines: 2,
                                ),
                              ],
                              // ID
                              pw.SizedBox(height: 2),
                              pw.Text(
                                getId(item),
                                style: const pw.TextStyle(fontSize: 9, color: PdfColors.grey700),
                              ),
                              // Détails supplémentaires
                              if (getDetails != null) ...[
                                pw.SizedBox(height: 4),
                                ...getDetails(item).take(4).map((line) {
                                  return pw.Padding(
                                    padding: const pw.EdgeInsets.only(bottom: 1),
                                    child: pw.Text(
                                      _truncate(line, 35),
                                      style: const pw.TextStyle(fontSize: 7, color: PdfColors.grey800),
                                    ),
                                  );
                                }),
                              ],
                            ],
                          ),
                        ),
                      ],
                    ),
                  );
                }),
              ),
            ),
          ),
        ),
      );
    }
  }
  /// Nettoie le cache (logo)
  static void clearCache() {
    _cachedLogoBytes = null;
    _logoLoadAttempted = false;
  }
}