<?php

namespace App\Exports;

use App\Models\Appointments;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\AfterSheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Border;
use Illuminate\Http\Request;
use Carbon\Carbon;

class AppointmentPaymentRelationExport implements FromCollection, WithHeadings, WithMapping, WithEvents
{
    protected $request;

    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    /**
     * @return \Illuminate\Support\Collection
     */
    public function collection()
    {
        $query = Appointments::with([
                'payment', 
                'payment.children', 
                'tags', 
                'patient', 
                'user',
                'payment.currency',
                'payment.paymentMethod',
                'payment.children.currency',
                'payment.children.paymentMethod'
            ])
            ->orderBy('date', 'desc');
            
        // Filtrar por estado de pago si se especifica
        if ($this->request->has('payment_status')) {
            if ($this->request->payment_status === 'with_payment') {
                // Una cita se considera pagada si:
                // 1. Tiene status = 2 (Finalizada) y existe un pago
                $query->where('status', 2)->whereHas('payment');
            } elseif ($this->request->payment_status === 'without_payment') {
                // Una cita se considera no pagada si:
                // 1. Tiene status = 3 (Cancelada)
                // 2. O si no tiene estado 2 (Finalizada) o no tiene un pago
                $query->where(function($q) {
                    $q->where('status', 3)
                      ->orWhere(function($subQ) {
                          $subQ->where(function($statusQ) {
                              $statusQ->where('status', '!=', 2)->orWhereNull('status');
                          })->orWhereDoesntHave('payment');
                      });
                });
            }
        }
        
        // Filtrar por etiqueta si se especifica
        if ($this->request->has('tag_id') && $this->request->tag_id) {
            $query->whereHas('tags', function($q) {
                $q->where('appointment_tag_id', $this->request->tag_id);
            });
        }
        
        // Filtrar por doctor si se especifica
        if ($this->request->has('doctor_id') && $this->request->doctor_id) {
            $query->where('users_id', $this->request->doctor_id);
        }
        
        // Filtrar por rango de fechas si se especifica
        if ($this->request->has('date_from') && $this->request->date_from) {
            $query->whereDate('date', '>=', $this->request->date_from);
        }
        
        if ($this->request->has('date_to') && $this->request->date_to) {
            $query->whereDate('date', '<=', $this->request->date_to);
        }
        
        return $query->get();
    }

    /**
     * @var Appointments $appointment
     */
    public function map($appointment): array
    {
        // Determinar el estado de la cita
        $estadoCita = 'Pendiente';
        if ($appointment->status == 2) {
            $estadoCita = 'Concretada';
        } elseif ($appointment->status == 3) {
            $estadoCita = 'No concretada';
        } elseif ($appointment->status == 1) {
            $estadoCita = 'Confirmada';
        } elseif ($appointment->status == 4) {
            $estadoCita = 'No asistió';
        }

        // Inicializar datos de pago principal
        $pagoPrincipal = [
            'Código' => $appointment->code,
            'Tipo de Pago' => 'Principal',
            'Fecha' => Carbon::parse($appointment->date)->format('d/m/Y H:i'),
            'Paciente' => $appointment->patient->firstname . ' ' . $appointment->patient->lastname ?? 'N/A',
            'Doctor' => $appointment->user->profile->firstname . ' ' . $appointment->user->profile->lastname ?? 'N/A',
            'Etiquetas' => $this->formatTags($appointment->tags),
            'Estado Cita' => $estadoCita,
            'Estado de Pago' => $this->getEstadoPago($appointment),
            'Monto' => $appointment->payment ? number_format($appointment->payment->amount, 2) : '0.00',
            'Moneda' => $appointment->payment ? ($appointment->payment->currency->code ?? '') : '',
            'Método de Pago' => $appointment->payment ? ($appointment->payment->paymentMethod->title ?? 'N/A') : '-',
            'Referencia' => $appointment->payment ? ($appointment->payment->reference ?? 'N/A') : '-',
            'Comentarios' => $appointment->payment ? ($appointment->payment->comments ?? '') : '',
            'Fecha de Pago' => $appointment->payment ? Carbon::parse($appointment->payment->created_at)->format('d/m/Y H:i') : '',
        ];

        $rows = [];
        
        // Agregar fila del pago principal si existe
        if ($appointment->payment) {
            $rows[] = $pagoPrincipal;
            
            // Agregar filas de pagos hijos si existen
            if ($appointment->payment->children && $appointment->payment->children->isNotEmpty()) {
                foreach ($appointment->payment->children as $childPayment) {
                    $rows[] = [
                        'Código' => $appointment->code . '-' . $childPayment->id,
                        'Tipo de Pago' => 'Adicional',
                        'Fecha' => Carbon::parse($childPayment->created_at)->format('d/m/Y H:i'),
                        'Paciente' => $appointment->patient->firstname . ' ' . $appointment->patient->lastname ?? 'N/A',
                        'Doctor' => $appointment->user->profile->firstname . ' ' . $appointment->user->profile->lastname ?? 'N/A',
                        'Etiquetas' => $this->formatTags($appointment->tags),
                        'Estado Cita' => $estadoCita,
                        'Estado de Pago' => 'Pagado', // Los pagos hijos siempre están pagados
                        'Monto' => number_format($childPayment->amount, 2),
                        'Moneda' => $childPayment->currency->code ?? '',
                        'Método de Pago' => $childPayment->paymentMethod->title ?? 'N/A',
                        'Referencia' => $childPayment->reference ?? 'N/A',
                        'Comentarios' => $childPayment->comments ?? '',
                        'Fecha de Pago' => Carbon::parse($childPayment->created_at)->format('d/m/Y H:i'),
                    ];
                }
            }
        } else {
            // Si no hay pago, agregar solo la fila con datos básicos
            $rows[] = $pagoPrincipal;
        }

        return $rows;
    }

    public function headings(): array
    {
        return [
            'Código',
            'Tipo de Pago',
            'Fecha',
            'Paciente',
            'Doctor',
            'Etiquetas',
            'Estado Cita',
            'Estado de Pago',
            'Monto',
            'Moneda',
            'Método de Pago',
            'Referencia',
            'Comentarios',
            'Fecha de Pago',
        ];
    }

    /**
     * Determina el estado de pago de la cita
     */
    private function getEstadoPago($appointment)
    {
        if ($appointment->status == 2 && $appointment->hasPayment()) {
            return 'Pagado';
        } elseif ($appointment->status == 3) {
            return 'No pagado';
        }
        return 'Pendiente';
    }

    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            AfterSheet::class => function(AfterSheet $event) {
                // Obtener la hoja activa
                $sheet = $event->sheet;
                
                // Aplicar estilo a la cabecera
                $sheet->getStyle('A1:'.$sheet->getHighestColumn().'1')->applyFromArray([
                    'font' => [
                        'bold' => true,
                        'color' => ['argb' => 'FFFFFFFF'],
                    ],
                    'fill' => [
                        'fillType' => Fill::FILL_SOLID,
                        'startColor' => ['argb' => 'FF2B579A'], // Azul oscuro
                    ],
                    'borders' => [
                        'allBorders' => [
                            'borderStyle' => Border::BORDER_THIN,
                            'color' => ['argb' => 'FF000000'],
                        ],
                    ],
                    'alignment' => [
                        'horizontal' => Alignment::HORIZONTAL_CENTER,
                        'vertical' => Alignment::VERTICAL_CENTER,
                        'wrapText' => true,
                    ],
                ]);

                // Ajustar el ancho de las columnas automáticamente
                foreach (range('A', $sheet->getHighestColumn()) as $col) {
                    $sheet->getColumnDimension($col)->setAutoSize(true);
                }

                // Ajustar alturas de filas
                $sheet->getRowDimension(1)->setRowHeight(25);

                // Aplicar bordes a todas las celdas con datos
                $lastRow = $sheet->getHighestRow();
                $lastColumn = $sheet->getHighestColumn();
                
                if ($lastRow > 1) {
                    $sheet->getStyle('A2:'.$lastColumn.$lastRow)->applyFromArray([
                        'borders' => [
                            'allBorders' => [
                                'borderStyle' => Border::BORDER_THIN,
                                'color' => ['argb' => 'FFDDDDDD'],
                            ],
                        ],
                        'alignment' => [
                            'vertical' => Alignment::VERTICAL_TOP,
                            'wrapText' => true,
                        ],
                    ]);
                }


                // Ajustar el formato de las columnas
                $sheet->getStyle('A:A')->getNumberFormat()->setFormatCode('@'); // Código como texto
                $sheet->getStyle('I:I')->getNumberFormat()->setFormatCode('#,##0.00'); // Monto
                
                // Congelar la fila de encabezado
                $sheet->freezePane('A2');
                
                // Ajustar el zoom para mejor visualización
                $sheet->getParent()->getActiveSheet()->getSheetView()->setZoomScale(90);
            },
        ];
    }

    /**
     * Formatear las etiquetas para el Excel
     */
    private function formatTags($tags)
    {
        if (!$tags || $tags->isEmpty()) {
            return '';
        }

        return $tags->pluck('name')->implode(', ');
    }
}
