import 'dart:typed_data'; import 'package:flutter/services.dart' show rootBundle; import 'package:intl/intl.dart'; import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; import 'package:printing/printing.dart'; class InsuranceAuthPdfService { /// Genera el documento PDF de Autorización de Seguro en formato Media Carta Vertical /// (5.5 x 8.5 pulgadas / 396 x 612 pt). static Future buildInsuranceAuthPdf({ required String doctorName, required String specialty, required String subspecialty, required String generalContact, required String arsName, required String patientName, required String surgeryText, required String diagnosisText, String? anesthesia, String? daysOfStay, DateTime? date, pw.Font? fontRegular, pw.Font? fontBold, pw.Font? fontTitle, String? logoSvg, }) async { final pdf = pw.Document(title: 'Autorización de seguro - $patientName'); final formattedDate = DateFormat('dd/MM/yyyy').format(date ?? DateTime.now()); // Formato Carta Vertical (8.5 x 11.0 pulgadas / 612 x 792 pt): // Todo el contenido abarca estrictamente la mitad superior de la hoja (5.5 pulgadas / 396 pt), // dejando la mitad inferior libre para corte o papel pre-cortado. const pageFormat = PdfPageFormat( 8.5 * PdfPageFormat.inch, 11.0 * PdfPageFormat.inch, marginLeft: 54, marginRight: 54, marginTop: 20, marginBottom: 20, ); // Tipografías estándar con fallback a fuentes base PDF si no hay conexión a internet pw.Font regular = fontRegular ?? pw.Font.helvetica(); pw.Font bold = fontBold ?? pw.Font.helveticaBold(); pw.Font titleFont = fontTitle ?? pw.Font.timesBoldItalic(); if (fontRegular == null || fontBold == null || fontTitle == null) { try { regular = await PdfGoogleFonts.robotoRegular(); bold = await PdfGoogleFonts.robotoBold(); titleFont = await PdfGoogleFonts.playfairDisplayItalic(); } catch (_) { regular = pw.Font.helvetica(); bold = pw.Font.helveticaBold(); titleFont = pw.Font.timesBoldItalic(); } } String? svgContent = logoSvg; if (svgContent == null) { try { svgContent = await rootBundle.loadString('assets/images/hidalyx_logo_blue.svg'); } catch (_) { svgContent = null; } } pdf.addPage( pw.Page( pageFormat: pageFormat, build: (pw.Context context) { return pw.Column( crossAxisAlignment: pw.CrossAxisAlignment.stretch, children: [ // Mitad superior de la hoja (máximo 5.5 pulgadas / 396 pt) pw.ConstrainedBox( constraints: const pw.BoxConstraints( maxHeight: 5.5 * PdfPageFormat.inch - 36, ), child: pw.Column( mainAxisSize: pw.MainAxisSize.min, crossAxisAlignment: pw.CrossAxisAlignment.stretch, children: [ // 1. Cabecera con Nombre del Doctor y Badge Sutil de Hidalyx Med pw.Stack( children: [ // Nombre y especialidad del doctor centrado pw.Align( alignment: pw.Alignment.center, child: pw.Column( children: [ pw.Text( doctorName.isNotEmpty ? doctorName : 'Dr. Luis A. Castro Sosa', style: pw.TextStyle( font: titleFont, fontSize: 22, fontWeight: pw.FontWeight.bold, color: PdfColor.fromHex('1E293B'), ), ), pw.SizedBox(height: 3), if (specialty.isNotEmpty) pw.Text( specialty.toUpperCase(), style: pw.TextStyle( font: bold, fontSize: 10.5, letterSpacing: 0.5, color: PdfColor.fromHex('0F172A'), ), ), if (subspecialty.isNotEmpty) ...[ pw.SizedBox(height: 2), pw.Text( subspecialty.toUpperCase(), textAlign: pw.TextAlign.center, style: pw.TextStyle( font: regular, fontSize: 8.5, color: PdfColor.fromHex('475569'), ), ), ], pw.SizedBox(height: 3), pw.Text( 'Fecha: $formattedDate', style: pw.TextStyle( font: regular, fontSize: 9.5, color: PdfColor.fromHex('334155'), ), ), ], ), ), // Badge sutil de Hidalyx Med en la esquina superior derecha pw.Positioned( top: 0, right: 0, child: pw.Row( mainAxisSize: pw.MainAxisSize.min, crossAxisAlignment: pw.CrossAxisAlignment.center, children: [ if (svgContent != null && svgContent.isNotEmpty) ...[ pw.Opacity( opacity: 0.6, child: pw.SvgImage( svg: svgContent, width: 7.5, height: 7.5, ), ), pw.SizedBox(width: 3), ], pw.Text( 'hidalyx.com', style: pw.TextStyle( font: regular, fontSize: 6.0, color: PdfColor.fromHex('94A3B8'), ), ), ], ), ), ], ), pw.SizedBox(height: 6), // Línea divisoria decorativa del membrete pw.Container( height: 1, color: PdfColor.fromHex('CBD5E1'), ), pw.SizedBox(height: 8), // 2. Encabezado de la Orden Médica (Símbolo Rx) pw.Row( crossAxisAlignment: pw.CrossAxisAlignment.center, children: [ pw.Container( padding: const pw.EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: pw.BoxDecoration( color: PdfColor.fromHex('E2E8F0'), borderRadius: pw.BorderRadius.circular(4), ), child: pw.Text( 'Rx', style: pw.TextStyle( font: bold, fontSize: 12, color: PdfColor.fromHex('00A65A'), ), ), ), pw.SizedBox(width: 8), pw.Text( 'SOLICITUD DE AUTORIZACIÓN QUIRÚRGICA', style: pw.TextStyle( font: bold, fontSize: 10, letterSpacing: 0.5, color: PdfColor.fromHex('475569'), ), ), ], ), pw.SizedBox(height: 8), // 3. Contenido Formal idéntico a AlfaMedical pw.Column( crossAxisAlignment: pw.CrossAxisAlignment.stretch, mainAxisSize: pw.MainAxisSize.min, children: [ // Señores ARS pw.RichText( text: pw.TextSpan( children: [ pw.TextSpan( text: 'Señores ARS: ', style: pw.TextStyle(font: bold, fontSize: 11, color: PdfColor.fromHex('1E293B')), ), pw.TextSpan( text: arsName.isNotEmpty ? arsName : '____________________________________', style: pw.TextStyle(font: regular, fontSize: 11, color: PdfColor.fromHex('0F172A')), ), ], ), ), pw.SizedBox(height: 6), // Favor autorizar al Sr. (a) pw.RichText( text: pw.TextSpan( children: [ pw.TextSpan( text: 'Favor autorizar al Sr. (a): ', style: pw.TextStyle(font: bold, fontSize: 11, color: PdfColor.fromHex('1E293B')), ), pw.TextSpan( text: patientName.isNotEmpty ? patientName : '___________________________', style: pw.TextStyle(font: regular, fontSize: 11, color: PdfColor.fromHex('0F172A')), ), ], ), ), pw.SizedBox(height: 6), // La cirugía de: pw.RichText( text: pw.TextSpan( children: [ pw.TextSpan( text: 'La cirugía de: ', style: pw.TextStyle(font: bold, fontSize: 11, color: PdfColor.fromHex('1E293B')), ), pw.TextSpan( text: surgeryText.trim().isNotEmpty ? surgeryText.trim() : '___________________________', style: pw.TextStyle(font: regular, fontSize: 11, color: PdfColor.fromHex('0F172A')), ), ], ), ), pw.SizedBox(height: 6), // Diagnóstico pw.RichText( text: pw.TextSpan( children: [ pw.TextSpan( text: 'Diagnóstico: ', style: pw.TextStyle(font: bold, fontSize: 11, color: PdfColor.fromHex('1E293B')), ), pw.TextSpan( text: diagnosisText.trim().isNotEmpty ? diagnosisText.trim() : '___________________________', style: pw.TextStyle(font: regular, fontSize: 11, color: PdfColor.fromHex('0F172A')), ), ], ), ), pw.SizedBox(height: 6), // Bajo Anestesia y Días de ingreso if ((anesthesia != null && anesthesia.trim().isNotEmpty) || (daysOfStay != null && daysOfStay.trim().isNotEmpty)) ...[ pw.RichText( text: pw.TextSpan( children: [ if (anesthesia != null && anesthesia.trim().isNotEmpty) ...[ pw.TextSpan( text: 'Bajo Anestesia: ', style: pw.TextStyle(font: bold, fontSize: 11, color: PdfColor.fromHex('1E293B')), ), pw.TextSpan( text: anesthesia.trim(), style: pw.TextStyle(font: regular, fontSize: 11, color: PdfColor.fromHex('0F172A')), ), ], if (daysOfStay != null && daysOfStay.trim().isNotEmpty) ...[ pw.TextSpan( text: ' Con ', style: pw.TextStyle(font: bold, fontSize: 11, color: PdfColor.fromHex('1E293B')), ), pw.TextSpan( text: '${daysOfStay.trim()} Días de ingreso', style: pw.TextStyle(font: regular, fontSize: 11, color: PdfColor.fromHex('0F172A')), ), ], ], ), ), ], ], ), pw.SizedBox(height: 10), // Línea divisoria decorativa previa al pie pw.Container( height: 0.5, color: PdfColor.fromHex('CBD5E1'), ), pw.SizedBox(height: 5), // 4. Pie de página con Contacto del Consultorio if (generalContact.isNotEmpty) ...[ pw.Container( padding: const pw.EdgeInsets.only(top: 4), child: pw.Text( generalContact.toUpperCase(), textAlign: pw.TextAlign.center, style: pw.TextStyle( font: regular, fontSize: 6.8, color: PdfColor.fromHex('64748B'), lineSpacing: 1.5, ), ), ), ], pw.SizedBox(height: 3), // Confirmación institucional pw.Center( child: pw.Text( 'Documento médico emitido electrónicamente', style: pw.TextStyle( font: regular, fontSize: 6.0, color: PdfColor.fromHex('94A3B8'), ), ), ), ], ), ), ], ); }, ), ); return pdf.save(); } /// Envía a imprimir directamente o abre el diálogo nativo de impresión/PDF. static Future printInsuranceAuth({ required String doctorName, required String specialty, required String subspecialty, required String generalContact, required String arsName, required String patientName, required String surgeryText, required String diagnosisText, String? anesthesia, String? daysOfStay, DateTime? date, }) async { final pdfBytes = await buildInsuranceAuthPdf( doctorName: doctorName, specialty: specialty, subspecialty: subspecialty, generalContact: generalContact, arsName: arsName, patientName: patientName, surgeryText: surgeryText, diagnosisText: diagnosisText, anesthesia: anesthesia, daysOfStay: daysOfStay, date: date, ); await Printing.layoutPdf( onLayout: (PdfPageFormat format) async => pdfBytes, name: 'Autorizacion_Seguro_${patientName.replaceAll(' ', '_')}', ); } }