import 'dart:io';

import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;

import '../models/work_order.dart';

enum PdfReportType {
  client(
    label: 'Cliente',
    description: 'Incluye mano de obra, repuestos y valores.',
    fileSegment: 'cliente',
  ),
  certifier(
    label: 'Empresa certificadora',
    description: 'Omite repuestos y toda la información económica.',
    fileSegment: 'certificadora',
  );

  const PdfReportType({
    required this.label,
    required this.description,
    required this.fileSegment,
  });

  final String label;
  final String description;
  final String fileSegment;
}

class PdfService {
  static const _reportFilePrefix = 'OT_v12_';

  bool isCurrentReport(String filePath, {PdfReportType? type}) {
    final expectedPrefix = type == null
        ? _reportFilePrefix
        : '$_reportFilePrefix${type.fileSegment}_';
    return p.basename(filePath).startsWith(expectedPrefix);
  }

  Future<String> generate(
    WorkOrder order, {
    required PdfReportType type,
  }) async {
    final reportBytes = await build(order, type: type);
    final documents = await getApplicationDocumentsDirectory();
    final reportDirectory = Directory(
      p.join(documents.path, 'ot_movil', 'reports'),
    );
    await reportDirectory.create(recursive: true);
    final shortId = order.id.replaceAll('-', '').substring(0, 8);
    final reportPath = p.join(
      reportDirectory.path,
      '$_reportFilePrefix${type.fileSegment}_'
      '${DateFormat('yyyyMMdd_HHmm').format(DateTime.now())}_$shortId.pdf',
    );
    await File(reportPath).writeAsBytes(reportBytes, flush: true);
    return reportPath;
  }

  Future<Uint8List> build(
    WorkOrder order, {
    required PdfReportType type,
  }) async {
    final document = pw.Document(
      title: 'Orden de trabajo - ${order.title}',
      author: 'SMoya Gasfiter',
      subject: 'Informe de mantenimiento para ${type.label.toLowerCase()}',
    );
    final logoData = await rootBundle.load(
      'assets/pdf/simon_moya_report_logo.png',
    );
    final logo = pw.MemoryImage(
      logoData.buffer.asUint8List(
        logoData.offsetInBytes,
        logoData.lengthInBytes,
      ),
    );
    final signatureData = await rootBundle.load(
      'assets/pdf/simon_moya_signature.png',
    );
    final signature = pw.MemoryImage(
      signatureData.buffer.asUint8List(
        signatureData.offsetInBytes,
        signatureData.lengthInBytes,
      ),
    );
    final taskPhotos = <String, _TaskImages>{};
    for (final task in order.tasks) {
      taskPhotos[task.id] = await _loadTaskImages(task);
    }

    const primary = PdfColor.fromInt(0xFF0B5C5E);
    const dark = PdfColor.fromInt(0xFF163334);
    const muted = PdfColor.fromInt(0xFF5F6F70);
    const pale = PdfColor.fromInt(0xFFE7F1F0);
    final dateFormat = DateFormat('dd/MM/yyyy HH:mm');
    final priceFormat = NumberFormat.decimalPattern('es_CL');

    document.addPage(
      pw.MultiPage(
        pageTheme: pw.PageTheme(
          pageFormat: PdfPageFormat.a4,
          margin: const pw.EdgeInsets.fromLTRB(38, 42, 38, 42),
        ),
        header: (context) => _reportHeader(
          order,
          logo,
          type: type,
          primary: primary,
          dark: dark,
          muted: muted,
        ),
        footer: (context) => _reportFooter(context, muted),
        build: (context) => [
          pw.SizedBox(height: 12),
          pw.Text(
            order.title,
            style: pw.TextStyle(
              color: dark,
              fontSize: 21,
              fontWeight: pw.FontWeight.bold,
            ),
          ),
          pw.SizedBox(height: 6),
          pw.Text(
            'Orden de trabajo finalizada',
            style: const pw.TextStyle(color: primary, fontSize: 9),
          ),
          pw.SizedBox(height: 15),
          pw.Container(
            padding: const pw.EdgeInsets.symmetric(horizontal: 10, vertical: 9),
            decoration: pw.BoxDecoration(
              color: pale,
              borderRadius: pw.BorderRadius.circular(7),
            ),
            child: pw.Row(
              children: [
                _summaryItem(
                  'Creada',
                  dateFormat.format(order.createdAt.toLocal()),
                  dark,
                  muted,
                ),
                _summaryDivider(),
                _summaryItem(
                  'Finalizada',
                  dateFormat.format(
                    (order.completedAt ?? order.updatedAt).toLocal(),
                  ),
                  dark,
                  muted,
                ),
                _summaryDivider(),
                _summaryItem(
                  'Contenido',
                  '${order.tasks.length} tareas - ${order.totalPhotos} fotos',
                  dark,
                  muted,
                ),
                if (type == PdfReportType.client) ...[
                  _summaryDivider(),
                  _summaryItem(
                    'Total OT',
                    '\$${priceFormat.format(order.totalCost)}',
                    dark,
                    muted,
                  ),
                ],
              ],
            ),
          ),
          pw.SizedBox(height: 20),
          ...order.tasks.expand(
            (task) => _taskWidgets(
              task,
              taskPhotos[task.id]!,
              primary: primary,
              dark: dark,
              muted: muted,
              pale: pale,
              priceFormat: priceFormat,
              includeParts: type == PdfReportType.client,
            ),
          ),
          if (type == PdfReportType.client) ...[
            pw.SizedBox(height: 2),
            _costSummary(
              order,
              primary: primary,
              dark: dark,
              muted: muted,
              pale: pale,
              priceFormat: priceFormat,
            ),
          ],
          pw.SizedBox(height: 8),
          _signatureBlock(signature, dark: dark, muted: muted),
        ],
      ),
    );

    return document.save();
  }

  pw.Widget _reportHeader(
    WorkOrder order,
    pw.ImageProvider logo, {
    required PdfReportType type,
    required PdfColor primary,
    required PdfColor dark,
    required PdfColor muted,
  }) {
    return pw.Container(
      height: 78,
      padding: const pw.EdgeInsets.only(bottom: 10),
      decoration: pw.BoxDecoration(
        border: pw.Border(bottom: pw.BorderSide(color: primary, width: 1.5)),
      ),
      child: pw.Row(
        mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
        children: [
          pw.SizedBox(
            width: 175,
            height: 67,
            child: pw.Image(
              logo,
              fit: pw.BoxFit.cover,
              alignment: pw.Alignment.center,
            ),
          ),
          pw.SizedBox(
            width: 245,
            child: pw.Column(
              crossAxisAlignment: pw.CrossAxisAlignment.end,
              children: [
                pw.Text(
                  'Informe para ${type.label.toLowerCase()}',
                  style: pw.TextStyle(color: muted, fontSize: 9),
                ),
                pw.SizedBox(height: 7),
                _headerDetail(
                  'Cliente',
                  order.details.client.isEmpty
                      ? 'No informado'
                      : order.details.client,
                  dark,
                  muted,
                ),
                pw.SizedBox(height: 3),
                _headerDetail(
                  'Dirección',
                  order.details.address.isEmpty
                      ? 'No informada'
                      : order.details.address,
                  dark,
                  muted,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  pw.Widget _reportFooter(pw.Context context, PdfColor muted) {
    return pw.Row(
      mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
      children: [
        pw.Text(
          'Generado por SMoya Gasfiter',
          style: pw.TextStyle(color: muted, fontSize: 8),
        ),
        pw.Text(
          'Página ${context.pageNumber} de ${context.pagesCount}',
          style: pw.TextStyle(color: muted, fontSize: 8),
        ),
      ],
    );
  }

  pw.Widget _headerDetail(
    String label,
    String value,
    PdfColor dark,
    PdfColor muted,
  ) {
    return pw.RichText(
      textAlign: pw.TextAlign.right,
      text: pw.TextSpan(
        children: [
          pw.TextSpan(
            text: '${label.toUpperCase()}: ',
            style: pw.TextStyle(
              color: muted,
              fontSize: 6.5,
              fontWeight: pw.FontWeight.bold,
              letterSpacing: .35,
            ),
          ),
          pw.TextSpan(
            text: value,
            style: pw.TextStyle(
              color: dark,
              fontSize: 7.5,
              fontWeight: pw.FontWeight.bold,
            ),
          ),
        ],
      ),
    );
  }

  pw.Widget _summaryItem(
    String label,
    String value,
    PdfColor dark,
    PdfColor muted,
  ) {
    return pw.Expanded(
      child: pw.Column(
        crossAxisAlignment: pw.CrossAxisAlignment.start,
        children: [
          pw.Text(
            label.toUpperCase(),
            style: pw.TextStyle(
              color: muted,
              fontSize: 6.5,
              fontWeight: pw.FontWeight.bold,
              letterSpacing: .55,
            ),
          ),
          pw.SizedBox(height: 3),
          pw.Text(
            value,
            style: pw.TextStyle(
              color: dark,
              fontSize: 8,
              fontWeight: pw.FontWeight.bold,
            ),
          ),
        ],
      ),
    );
  }

  pw.Widget _summaryDivider() {
    return pw.Container(
      height: 24,
      margin: const pw.EdgeInsets.symmetric(horizontal: 8),
      decoration: const pw.BoxDecoration(
        border: pw.Border(
          left: pw.BorderSide(color: PdfColor.fromInt(0xFFB8CFCD)),
        ),
      ),
    );
  }

  List<pw.Widget> _taskWidgets(
    WorkTask task,
    _TaskImages images, {
    required PdfColor primary,
    required PdfColor dark,
    required PdfColor muted,
    required PdfColor pale,
    required NumberFormat priceFormat,
    required bool includeParts,
  }) {
    return [
      pw.NewPage(freeSpace: includeParts && task.parts.isNotEmpty ? 220 : 145),
      pw.Container(
        padding: const pw.EdgeInsets.symmetric(horizontal: 12, vertical: 10),
        decoration: pw.BoxDecoration(
          color: dark,
          borderRadius: pw.BorderRadius.circular(5),
        ),
        child: pw.Row(
          children: [
            pw.Container(
              width: 23,
              height: 23,
              alignment: pw.Alignment.center,
              decoration: pw.BoxDecoration(
                color: primary,
                shape: pw.BoxShape.circle,
              ),
              child: pw.Text(
                '${task.position + 1}',
                style: pw.TextStyle(
                  color: PdfColors.white,
                  fontSize: 10,
                  fontWeight: pw.FontWeight.bold,
                ),
              ),
            ),
            pw.SizedBox(width: 9),
            pw.Expanded(
              child: pw.Text(
                task.title,
                style: pw.TextStyle(
                  color: PdfColors.white,
                  fontSize: 13,
                  fontWeight: pw.FontWeight.bold,
                ),
              ),
            ),
          ],
        ),
      ),
      pw.SizedBox(height: 10),
      pw.Text(
        'OBSERVACIÓN',
        style: pw.TextStyle(
          color: primary,
          fontSize: 8,
          fontWeight: pw.FontWeight.bold,
          letterSpacing: .8,
        ),
      ),
      pw.SizedBox(height: 4),
      pw.Container(
        width: double.infinity,
        padding: const pw.EdgeInsets.all(11),
        decoration: pw.BoxDecoration(
          color: pale,
          borderRadius: pw.BorderRadius.circular(4),
        ),
        child: pw.Text(
          task.observation,
          style: pw.TextStyle(color: dark, fontSize: 10, lineSpacing: 3),
        ),
      ),
      if (includeParts && task.parts.isNotEmpty) ...[
        pw.SizedBox(height: 13),
        ..._partsWidgets(
          task.parts,
          task.partsTotal,
          primary: primary,
          dark: dark,
          muted: muted,
          pale: pale,
          priceFormat: priceFormat,
        ),
      ],
      pw.SizedBox(height: 15),
      ..._photoSection(
        'ANTES DE LA MANTENCIÓN',
        images.before,
        primary: primary,
        muted: muted,
      ),
      pw.SizedBox(height: 14),
      ..._photoSection(
        'DESPUÉS DE LA MANTENCIÓN',
        images.after,
        primary: primary,
        muted: muted,
      ),
      pw.SizedBox(height: 28),
    ];
  }

  List<pw.Widget> _partsWidgets(
    List<TaskPart> parts,
    int subtotal, {
    required PdfColor primary,
    required PdfColor dark,
    required PdfColor muted,
    required PdfColor pale,
    required NumberFormat priceFormat,
  }) {
    final widgets = <pw.Widget>[
      pw.Row(
        children: [
          pw.Text(
            'REPUESTOS UTILIZADOS',
            style: pw.TextStyle(
              color: primary,
              fontSize: 8,
              fontWeight: pw.FontWeight.bold,
              letterSpacing: .7,
            ),
          ),
          pw.Spacer(),
          pw.Text(
            '${parts.length} ${parts.length == 1 ? 'repuesto' : 'repuestos'}',
            style: pw.TextStyle(color: muted, fontSize: 8),
          ),
        ],
      ),
      pw.SizedBox(height: 6),
      pw.Container(
        padding: const pw.EdgeInsets.symmetric(horizontal: 9, vertical: 6),
        decoration: pw.BoxDecoration(
          color: pale,
          borderRadius: pw.BorderRadius.circular(3),
        ),
        child: pw.Row(
          children: [
            pw.Expanded(
              child: pw.Text(
                'DESCRIPCIÓN',
                style: pw.TextStyle(
                  color: muted,
                  fontSize: 6.5,
                  fontWeight: pw.FontWeight.bold,
                ),
              ),
            ),
            pw.SizedBox(
              width: 90,
              child: pw.Text(
                'PRECIO',
                textAlign: pw.TextAlign.right,
                style: pw.TextStyle(
                  color: muted,
                  fontSize: 6.5,
                  fontWeight: pw.FontWeight.bold,
                ),
              ),
            ),
          ],
        ),
      ),
      for (final part in parts)
        pw.Container(
          padding: const pw.EdgeInsets.symmetric(horizontal: 9, vertical: 6),
          decoration: const pw.BoxDecoration(
            border: pw.Border(
              bottom: pw.BorderSide(
                color: PdfColor.fromInt(0xFFD6E0DF),
                width: .6,
              ),
            ),
          ),
          child: pw.Row(
            crossAxisAlignment: pw.CrossAxisAlignment.start,
            children: [
              pw.Expanded(
                child: pw.Text(
                  part.name,
                  style: pw.TextStyle(color: dark, fontSize: 8),
                ),
              ),
              pw.SizedBox(
                width: 90,
                child: pw.Text(
                  '\$${priceFormat.format(part.price)}',
                  textAlign: pw.TextAlign.right,
                  style: pw.TextStyle(
                    color: dark,
                    fontSize: 8,
                    fontWeight: pw.FontWeight.bold,
                  ),
                ),
              ),
            ],
          ),
        ),
      pw.Container(
        padding: const pw.EdgeInsets.only(top: 7),
        child: pw.Row(
          mainAxisAlignment: pw.MainAxisAlignment.end,
          children: [
            pw.Text(
              'Subtotal: ',
              style: pw.TextStyle(color: muted, fontSize: 8),
            ),
            pw.Text(
              '\$${priceFormat.format(subtotal)}',
              style: pw.TextStyle(
                color: primary,
                fontSize: 9,
                fontWeight: pw.FontWeight.bold,
              ),
            ),
          ],
        ),
      ),
    ];
    if (parts.length <= 8) {
      return [
        pw.Inseparable(
          child: pw.Column(
            crossAxisAlignment: pw.CrossAxisAlignment.stretch,
            children: widgets,
          ),
        ),
      ];
    }
    return widgets;
  }

  List<pw.Widget> _photoSection(
    String title,
    List<pw.ImageProvider> images, {
    required PdfColor primary,
    required PdfColor muted,
  }) {
    final widgets = <pw.Widget>[
      pw.Row(
        children: [
          pw.Text(
            title,
            style: pw.TextStyle(
              color: primary,
              fontSize: 8,
              fontWeight: pw.FontWeight.bold,
              letterSpacing: .7,
            ),
          ),
          pw.SizedBox(width: 8),
          pw.Text(
            '${images.length} ${images.length == 1 ? 'foto' : 'fotos'}',
            style: pw.TextStyle(color: muted, fontSize: 8),
          ),
        ],
      ),
      pw.SizedBox(height: 7),
    ];

    for (var index = 0; index < images.length; index += 3) {
      widgets.add(
        pw.Row(
          crossAxisAlignment: pw.CrossAxisAlignment.start,
          children: [
            for (var offset = 0; offset < 3; offset++) ...[
              pw.Expanded(
                child: index + offset < images.length
                    ? _pdfImage(images[index + offset])
                    : pw.SizedBox(),
              ),
              if (offset < 2) pw.SizedBox(width: 8),
            ],
          ],
        ),
      );
      widgets.add(pw.SizedBox(height: 8));
    }
    return widgets;
  }

  pw.Widget _costSummary(
    WorkOrder order, {
    required PdfColor primary,
    required PdfColor dark,
    required PdfColor muted,
    required PdfColor pale,
    required NumberFormat priceFormat,
  }) {
    pw.Widget costRow(String label, int value, {bool emphasize = false}) {
      return pw.Row(
        mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
        children: [
          pw.Text(
            label,
            style: pw.TextStyle(
              color: emphasize ? dark : muted,
              fontSize: emphasize ? 10 : 9,
              fontWeight: emphasize ? pw.FontWeight.bold : pw.FontWeight.normal,
            ),
          ),
          pw.Text(
            '\$${priceFormat.format(value)}',
            style: pw.TextStyle(
              color: emphasize ? primary : dark,
              fontSize: emphasize ? 11 : 9,
              fontWeight: pw.FontWeight.bold,
            ),
          ),
        ],
      );
    }

    return pw.Inseparable(
      child: pw.Container(
        width: double.infinity,
        padding: const pw.EdgeInsets.all(12),
        decoration: pw.BoxDecoration(
          color: pale,
          borderRadius: pw.BorderRadius.circular(6),
        ),
        child: pw.Column(
          crossAxisAlignment: pw.CrossAxisAlignment.stretch,
          children: [
            pw.Text(
              'RESUMEN DE COSTOS',
              style: pw.TextStyle(
                color: primary,
                fontSize: 8,
                fontWeight: pw.FontWeight.bold,
                letterSpacing: .7,
              ),
            ),
            pw.SizedBox(height: 9),
            costRow('Costo de mano de obra', order.laborCost),
            pw.SizedBox(height: 6),
            costRow('Total de repuestos', order.totalPartsCost),
            pw.SizedBox(height: 8),
            pw.Divider(color: muted, thickness: .5),
            pw.SizedBox(height: 6),
            costRow('Valor total de la OT', order.totalCost, emphasize: true),
          ],
        ),
      ),
    );
  }

  pw.Widget _signatureBlock(
    pw.ImageProvider signature, {
    required PdfColor dark,
    required PdfColor muted,
  }) {
    return pw.Inseparable(
      child: pw.Column(
        crossAxisAlignment: pw.CrossAxisAlignment.center,
        children: [
          pw.SizedBox(width: double.infinity, height: 8),
          pw.Text(
            'Atentamente',
            style: pw.TextStyle(color: muted, fontSize: 8),
          ),
          pw.SizedBox(height: 2),
          pw.SizedBox(
            width: 105,
            height: 78,
            child: pw.Image(signature, fit: pw.BoxFit.contain),
          ),
          pw.Text(
            'Simón Moya Salinas',
            style: pw.TextStyle(
              color: dark,
              fontSize: 10,
              fontWeight: pw.FontWeight.bold,
            ),
          ),
          pw.SizedBox(height: 2),
          pw.Text(
            'C.I.: 9.990.302-3 - Instalador de gas autorizado SEC',
            style: pw.TextStyle(color: dark, fontSize: 8),
          ),
          pw.SizedBox(height: 2),
          pw.Text(
            'WhatsApp: 933922780',
            style: pw.TextStyle(color: muted, fontSize: 8),
          ),
        ],
      ),
    );
  }

  pw.Widget _pdfImage(pw.ImageProvider image) {
    return pw.Container(
      height: 115,
      decoration: pw.BoxDecoration(
        borderRadius: pw.BorderRadius.circular(4),
        border: pw.Border.all(
          color: const PdfColor.fromInt(0xFFD6E0DF),
          width: .7,
        ),
      ),
      child: pw.Center(child: pw.Image(image, fit: pw.BoxFit.contain)),
    );
  }

  Future<_TaskImages> _loadTaskImages(WorkTask task) async {
    final before = <pw.ImageProvider>[];
    final after = <pw.ImageProvider>[];
    for (final photo in task.photos) {
      final file = File(photo.path);
      if (!await file.exists()) continue;
      final Uint8List bytes = await file.readAsBytes();
      final provider = pw.MemoryImage(bytes);
      if (photo.kind == PhotoKind.before) {
        before.add(provider);
      } else {
        after.add(provider);
      }
    }
    return _TaskImages(before: before, after: after);
  }
}

class _TaskImages {
  const _TaskImages({required this.before, required this.after});

  final List<pw.ImageProvider> before;
  final List<pw.ImageProvider> after;
}
