import 'dart:isolate';
import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:pdf/pdf.dart' as pdf;
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';

import '../../providers/reports_provider.dart';
import '../../utils/app_time.dart';

/// Captures all visible report charts via their [RepaintBoundary] keys
/// and generates a PDF document for export / printing.
class ReportPdfExport {
  ReportPdfExport._();

  /// Capture a [RepaintBoundary] as a PNG [Uint8List].
  ///
  /// Yields to the event loop after each capture so the UI stays responsive.
  static Future<Uint8List?> _captureWidget(GlobalKey key) async {
    final boundary =
        key.currentContext?.findRenderObject() as RenderRepaintBoundary?;
    if (boundary == null) return null;

    final image = await boundary.toImage(pixelRatio: 1.5);
    final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
    // Yield to the event loop so the UI thread doesn't freeze
    await Future<void>.delayed(Duration.zero);
    return byteData?.buffer.asUint8List();
  }

  /// Generates the full report PDF from the given [captureKeys] map.
  ///
  /// [captureKeys] maps a human-readable chart title to the [GlobalKey]
  /// attached to that chart's [RepaintBoundary].
  ///
  /// [dateRange] is for display in the header.
  /// [enabledWidgets] filters which charts to include.
  static Future<Uint8List> generatePdf({
    required Map<String, GlobalKey> captureKeys,
    required ReportDateRange dateRange,
    required Set<ReportWidgetType> enabledWidgets,
  }) async {
    // Load fonts
    final regularFontData = await rootBundle.load(
      'assets/fonts/Roboto-Regular.ttf',
    );
    final boldFontData = await rootBundle.load('assets/fonts/Roboto-Bold.ttf');

    // Try to load logo (may not exist in all builds)
    Uint8List? logoBytes;
    try {
      final logoData = await rootBundle.load('assets/crmc_logo.png');
      logoBytes = logoData.buffer.asUint8List();
    } catch (_) {
      // Logo not available — skip
    }

    // ── Capture chart images on the main thread (needs render objects) ──
    final chartImages = <String, Uint8List>{};
    for (final entry in captureKeys.entries) {
      final bytes = await _captureWidget(entry.value);
      if (bytes != null) {
        chartImages[entry.key] = bytes;
      }
    }

    final dateRangeText = AppTime.formatDateRange(dateRange.dateTimeRange);
    final generated = AppTime.formatDate(AppTime.now());
    final dateLabel = dateRange.label;

    // ── Build the PDF on a background isolate so it doesn't freeze the UI ──
    return Isolate.run(() {
      return _buildPdfBytes(
        chartImages: chartImages,
        dateRangeText: dateRangeText,
        dateLabel: dateLabel,
        generated: generated,
        regularFontData: regularFontData.buffer.asUint8List(),
        boldFontData: boldFontData.buffer.asUint8List(),
        logoBytes: logoBytes,
      );
    });
  }

  /// Pure function that assembles the PDF document from raw data.
  /// Designed to run inside [Isolate.run].
  static Future<Uint8List> _buildPdfBytes({
    required Map<String, Uint8List> chartImages,
    required String dateRangeText,
    required String dateLabel,
    required String generated,
    required Uint8List regularFontData,
    required Uint8List boldFontData,
    Uint8List? logoBytes,
  }) {
    final regularFont = pw.Font.ttf(regularFontData.buffer.asByteData());
    final boldFont = pw.Font.ttf(boldFontData.buffer.asByteData());
    pw.MemoryImage? logoImage;
    if (logoBytes != null) {
      logoImage = pw.MemoryImage(logoBytes);
    }

    final doc = pw.Document();

    // One page per chart to avoid TooManyPagesException and keep layout simple
    // First chart gets the full header; subsequent ones get a compact header.
    var isFirst = true;
    for (final entry in chartImages.entries) {
      doc.addPage(
        pw.Page(
          pageFormat: pdf.PdfPageFormat.a4.landscape,
          margin: const pw.EdgeInsets.all(32),
          theme: pw.ThemeData.withFont(base: regularFont, bold: boldFont),
          build: (pw.Context ctx) {
            final header = isFirst
                ? pw.Column(
                    crossAxisAlignment: pw.CrossAxisAlignment.start,
                    children: [
                      pw.Row(
                        crossAxisAlignment: pw.CrossAxisAlignment.center,
                        children: [
                          if (logoImage != null)
                            pw.Container(
                              width: 50,
                              height: 50,
                              child: pw.Image(logoImage),
                            ),
                          if (logoImage != null) pw.SizedBox(width: 12),
                          pw.Column(
                            crossAxisAlignment: pw.CrossAxisAlignment.start,
                            children: [
                              pw.Text(
                                'TasQ Report',
                                style: pw.TextStyle(
                                  fontSize: 20,
                                  fontWeight: pw.FontWeight.bold,
                                ),
                              ),
                              pw.Text(
                                '$dateLabel — $dateRangeText',
                                style: pw.TextStyle(
                                  fontSize: 11,
                                  color: pdf.PdfColors.grey700,
                                ),
                              ),
                            ],
                          ),
                          pw.Spacer(),
                          pw.Text(
                            'Generated: $generated',
                            style: pw.TextStyle(
                              fontSize: 9,
                              color: pdf.PdfColors.grey500,
                            ),
                          ),
                        ],
                      ),
                      pw.Divider(thickness: 0.5),
                      pw.SizedBox(height: 8),
                    ],
                  )
                : pw.Container(
                    margin: const pw.EdgeInsets.only(bottom: 8),
                    child: pw.Row(
                      mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
                      children: [
                        pw.Text(
                          'TasQ Report',
                          style: pw.TextStyle(
                            fontSize: 10,
                            color: pdf.PdfColors.grey600,
                          ),
                        ),
                        pw.Text(
                          dateRangeText,
                          style: pw.TextStyle(
                            fontSize: 10,
                            color: pdf.PdfColors.grey600,
                          ),
                        ),
                      ],
                    ),
                  );

            isFirst = false;

            return pw.Column(
              crossAxisAlignment: pw.CrossAxisAlignment.start,
              children: [
                header,
                pw.Text(
                  entry.key,
                  style: pw.TextStyle(
                    fontSize: 13,
                    fontWeight: pw.FontWeight.bold,
                  ),
                ),
                pw.SizedBox(height: 6),
                pw.Expanded(
                  child: pw.Center(
                    child: pw.Image(
                      pw.MemoryImage(entry.value),
                      fit: pw.BoxFit.contain,
                    ),
                  ),
                ),
                pw.Container(
                  alignment: pw.Alignment.centerRight,
                  child: pw.Text(
                    'Page ${ctx.pageNumber}  •  Generated by TasQ',
                    style: pw.TextStyle(fontSize: 9, color: pdf.PdfColors.grey),
                  ),
                ),
              ],
            );
          },
        ),
      );
    }

    if (chartImages.isEmpty) {
      doc.addPage(
        pw.Page(
          pageFormat: pdf.PdfPageFormat.a4.landscape,
          margin: const pw.EdgeInsets.all(32),
          theme: pw.ThemeData.withFont(base: regularFont, bold: boldFont),
          build: (pw.Context ctx) => pw.Center(
            child: pw.Text(
              'No charts selected for export.',
              style: pw.TextStyle(fontSize: 14),
            ),
          ),
        ),
      );
    }

    return doc.save();
  }

  /// Show a print / share dialog for the generated PDF.
  static Future<void> sharePdf(Uint8List pdfBytes) async {
    await Printing.layoutPdf(
      onLayout: (_) => pdfBytes,
      name:
          'TasQ_Report_${AppTime.formatDate(AppTime.now()).replaceAll(' ', '_')}.pdf',
    );
  }
}
