<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\History;
use App\Models\Patients;
use App\Models\SectionType;
use App\Models\SectionHistory;
use App\Models\PhysicalExam;
use App\Models\Especiality;
use App\Models\MedicalReport;
use App\Models\ControlHistory;
use DateTime;
use Illuminate\Support\Facades\DB;
use App\PhysicalTest\PhysicalTest;
use Throwable;
use App\Exceptions\GlobalException;
use PDF;
use App\Helper\Helper;
use App\Models\Files;
use Illuminate\Support\Str;
use App\Models\HistoryConfiguration;
use App\Helper\ClinicIdentityHelper;



class HistoryController extends Controller
{

    /**
     * 
     */
    public function view(Request $request){
        try{
            $data = $request->all();
            return view("view-histories",$data);
        }catch(Throwable $th){
            throw new GlobalException($th->getMessage());
        }
    }

    /**
     * Vista para configurar historias
     */
    public function configureHistory(Request $request){
        try{
            $data = $request->all();
            $especialities = Especiality::getEspecialities();
            $sectionTypes = SectionType::all();
            
            // Obtener la configuración existente si hay una especialidad seleccionada
            $configuration = null;
            if (isset($data['especiality_id'])) {
                $configuration = HistoryConfiguration::where('especiality_id', $data['especiality_id'])->first();
            }
            
            // Obtener los exámenes médicos del PhysicalTest
            $physicalTest = new PhysicalTest();
            $fields = $physicalTest->getFields();
            
            // Separar los campos en categorías
            $vitalSigns = [];
            $physicalExam = [];
            $studiesAndComments = [];
            
            foreach ($fields as $key => $value) {
                if (in_array($key, ['p1','p2','p3','Weight', 'Size', 'TA', 'Temp', 'C_FC', 'FR'])) {
                    $vitalSigns[$key] = $value;
                } elseif (in_array($key, ['General', 'Skin', 'Head', 'Eyes', 'ORL', 'Neck', 'Cardio_Pulmonary', 'Abdomen', 'Genitourinary_and_rectal', 'Extremities', 'Neurologist'])) {
                    $physicalExam[$key] = $value;
                } elseif (in_array($key, ['Paraclinical_Studies', 'Comment'])) {
                    $studiesAndComments[$key] = $value;
                }
            }
            
            return view("configure-history", [
                "especialities" => $especialities,
                "sectionTypes" => $sectionTypes,
                "vitalSigns" => $vitalSigns,
                "physicalExam" => $physicalExam,
                "studiesAndComments" => $studiesAndComments,
                "configuration" => $configuration
            ]);
        } catch (Throwable $th) {
            throw new GlobalException($th->getMessage());
        }
    }

  
     /**
     * 
     */
    public function update(Request $request,PhysicalTest $physicalTest){
        try {
            $patients;
            $data = $request->all();
            $id = $data["id"];
            $model = History::find($id);
            $sectionTypes = SectionType::where("section_type_id",NULL)->get();
            if($model === null)
                throw new GlobalException(__("error-500.messageNoSearch"));
             if(!($request->method() === "POST")){
                $patients = Patients::all();
                
                // Obtener la configuración si hay una especialidad seleccionada
                $configuration = null;
                if (isset($model->especiality)) {
                    $configuration = HistoryConfiguration::where('especiality_id', $model->especiality)->first();
                }
                
                return view("update-history",[
                    "history"=>$model,
                    "patients"=>$patients,
                    "sectionTypes"=>$sectionTypes,
                    "physicalTest"=>$physicalTest,
                    "new"=>false,
                    "configuration"=>$configuration
                ]);
             }
             DB::beginTransaction();
             $this->prepareAndSaveDataHistory($request,$model,true);
             DB::commit();
             return redirect()->route("/admin/view-histories",[
                 "create"=>true
             ]);
            } catch (Throwable $th) {
             DB::rollback();
             throw new GlobalException($th->getMessage());
     
            }
         }
  
    
    /**
     * 
     */
    public function create(Request $request, PhysicalTest $physicalTest){
        try {
            $patients;
            $model = new History();
            $sectionTypes = SectionType::where("section_type_id", NULL)->get();
            
            if(!($request->method() === "POST")){
                $data = $request->all();
                $patients = Patients::all();
                
                // Obtener la configuración si hay una especialidad seleccionada
                $configuration = null;
                if (isset($data['especiality_id'])) {
                    $configuration = HistoryConfiguration::where('especiality_id', $data['especiality_id'])->first();
                }
                
                return view("create-history", [
                    "history" => $model,
                    "sectionTypes" => $sectionTypes,
                    "patients" => $patients,
                    "physicalTest" => $physicalTest,
                    "new" => true,
                    "configuration" => $configuration
                ]);
            }

            
            DB::beginTransaction();
            $this->prepareAndSaveDataHistory($request, $model);
            DB::commit();
            
            return redirect()->route("/admin/view-histories", [
                "create" => true
            ]);
        } catch (Throwable $th) {
            DB::rollback();
            throw new GlobalException($th->getMessage());
        }
    }

    /**
     * 
     */
    public function detail(Request $request){
       try{
        $data = $request->all();
        $id = $data["id"];
        $model = History::find($id);
        if($model === null)
            throw new GlobalException(__("error-500.messageNoSearch"));
        return view("detail-history",[
            "model"=>$model,
            "controlHistories"=>ControlHistory::where("history_id",$id)->get(),
            "modelMedicalReports"=>MedicalReport::where("patients_id",$model->patient()->first()->id)->get(),
            "especialities"=>Especiality::getEspecialities()
        ]);
       }catch(Throwable $th){
        throw new GlobalException($th->getMessage());
        }
    }

    /**
     * 
     */
    private function prepareAndSaveDataHistory($request,$model, $isUpdate = false){
        try {
            $data = $request->all();
            // Recopilar todos los campos que tengan el prefijo "cie-"
            $cieCodes = [];
            foreach ($data as $key => $value) {
                if (strpos($key, 'cie-') === 0) {
                    $cieCodes[] = $value;
                }
            }
            // Almacenar los códigos en el campo cie_code, separados por coma
            $model->cie_code = implode(',', $cieCodes);
            $model->patients_id = $data["patients_id"];
            $model->title     = $data["title"];
            $model->summary     = $data["summary"];
            $model->diagnosis     = $data["diagnosis"];
            $model->especiality = $data["especiality"];
            $model->save();
            
            // Verificar si existe una configuración personalizada para la especialidad
            $configuration = HistoryConfiguration::where('especiality_id', $model->especiality)->first();
            
            // Procesar secciones de historia (antecedentes)
            $sectionHistories = $this->getSectionHistoryFromRequest($data, $model, $isUpdate, $configuration);
            
            // Procesar examen físico
            $physicalExam = $this->getPhysicalExamFromRequest($data, $model, $isUpdate, $configuration);
            
            // Guardar secciones de historia
            foreach($sectionHistories as $sectionHistory){
                $sectionHistory->save();
            }
            
            // Guardar examen físico
            $physicalExam->save();

            // Procesar archivos
            if ($request->has('fileuploads')) {
                $this->validate($request, [
                    'fileuploads' => 'required',
                    'fileuploads.*' => 'mimes:doc,docx,pdf,png,jpg,jpeg'
                ]);
                $files = $request->file('fileuploads');
                Helper::processFileUploadHistoryAndControl($files,'fileuploads',$model->id,null);
            }
        }catch(Throwable $th){
            throw new GlobalException($th->getMessage());
        }
    }


    /**
     * 
     */
    public function uploadFiles(Request $request){
        $data = $request->all();
        $historyId = $data["history_id"];
        $controlId = null;
        $patientId = $data["patientId"];
        if(isset($data["control_id"]))
            $controlId = $data["control_id"];
            $this->validate($request, [
                'fileuploads' => 'required',
                'fileuploads.*' => 'mimes:doc,docx,pdf,png,jpg,jpeg'
            ]);
        $files = $request->file('fileuploads');
        Helper::processFileUploadHistoryAndControl($files,'fileuploads',$historyId,$controlId);
        return redirect()->route("/admin/detail-history",[
            "id"=>$historyId,
            "patientId"=>$patientId
        ])->with('success', __("com-form-history.successFileLoaded"));;
    }

    /**
     * Procesa los datos de examen físico de la solicitud
     */
    private function getPhysicalExamFromRequest($data, $history, $isUpdate = false, $configuration = null)
    {
        try {
            $physicalExamData = [];
            
            // 1. Filtrar y sanitizar datos
            foreach ($data as $key => $value) {
                if (strpos($key, 'physical-exam-') === 0) {
                    $cleanKey = str_replace('physical-exam-', '', $key);
                    
                    // Verificar si este examen está en la configuración
                    if ($configuration && !empty($configuration->medical_exams)) {
                        if (!in_array($cleanKey, $configuration->medical_exams)) {
                            continue; // Omitir exámenes que no están en la configuración
                        }
                    }
                    
                    $physicalExamData[$cleanKey] = Helper::sanitizeInput($value);
                }
            }
            
            // 2. Buscar o crear registro
            $physicalExam = $isUpdate
                ? PhysicalExam::firstOrNew([
                    'history_id' => $history->id,
                ])
                : new PhysicalExam();

            // 3. Generar ID seguro solo para nuevos registros
            if (!$physicalExam->exists) {
                $physicalExam->id = Str::uuid(); 
                $physicalExam->history_id = $history->id;
            }

            // 4. Si estamos actualizando, preservar valores existentes que no están en la configuración actual
            if ($isUpdate && $configuration && !empty($configuration->medical_exams)) {
                $existingData = json_decode($physicalExam->value, true) ?: [];
                
                // Filtrar datos existentes para mantener solo los que no se pueden editar en la configuración actual
                $preservedData = array_filter(
                    $existingData, 
                    function($key) use ($configuration) {
                        return !in_array($key, $configuration->medical_exams);
                    }, 
                    ARRAY_FILTER_USE_KEY
                );
                
                // Combinar datos preservados con nuevos datos
                $physicalExamData = array_merge($preservedData, $physicalExamData);
            }

            // 5. Asignar valores
            $physicalExam->value = !empty($physicalExamData) 
                ? json_encode($physicalExamData, JSON_PRETTY_PRINT)
                : null;

            return $physicalExam;
            
        } catch (Throwable $th) {
            throw new GlobalException($th->getMessage());
        }
    }

    /**
     * Obtiene el historial de secciones a partir de los datos de la solicitud.
     */
    private function getSectionHistoryFromRequest($data, $history, $isUpdate = false, $configuration = null) {
        try {
            $sectionHistories = [];
            $processedSectionTypes = []; // Para rastrear qué secciones ya procesamos
            
            // 1. Procesar datos del formulario
            foreach ($data as $key => $value) {
                if (strpos($key, '_value') !== false) {
                    $sectionTypeKey = str_replace('_value', '', $key);
                    $sectionType = SectionType::where('key', $sectionTypeKey)->first();
                    
                    if (!$sectionType) {
                        continue; // Omitir si no se encuentra el tipo de sección
                    }
                    
                    // Verificar si esta sección está en la configuración
                    if ($configuration && !empty($configuration->section_types)) {
                        if (!in_array($sectionType->id, $configuration->section_types)) {
                            continue; // Omitir secciones que no están en la configuración
                        }
                    }
                    
                    $processedSectionTypes[] = $sectionType->id;

                    // Buscar o crear SectionHistory
                    $sectionHistory = $isUpdate 
                        ? SectionHistory::firstOrNew([
                            'history_id' => $history->id,
                            'section_type_id' => $sectionType->id
                        ])
                        : new SectionHistory();

                    // Configurar propiedades comunes
                    $sectionHistory->fill([
                        'title'   => __("backgrounds.{$sectionType->value}"),
                        'summary' => $value
                    ]);

                    // Asignar IDs solo si es nuevo
                    if (!$sectionHistory->exists) {
                        $sectionHistory->id = md5(uniqid($sectionTypeKey, true));
                        $sectionHistory->history_id = $history->id;
                        $sectionHistory->section_type_id = $sectionType->id;
                    }

                    $sectionHistories[] = $sectionHistory;
                }
            }
            
            // 2. Si estamos actualizando, incluir secciones existentes que no están en la configuración actual
            if ($isUpdate && $configuration && !empty($configuration->section_types)) {
                $existingSections = SectionHistory::where('history_id', $history->id)->get();
                
                foreach ($existingSections as $existingSection) {
                    // Si ya procesamos esta sección, omitirla
                    if (in_array($existingSection->section_type_id, $processedSectionTypes)) {
                        continue;
                    }
                    
                    // Si esta sección no está en la configuración actual, incluirla sin cambios
                    if (!in_array($existingSection->section_type_id, $configuration->section_types)) {
                        $sectionHistories[] = $existingSection;
                        $processedSectionTypes[] = $existingSection->section_type_id;
                    }
                }
            }

            return $sectionHistories;
        } catch (Throwable $th) {
            throw new GlobalException($th->getMessage());
        }
    }

    /**
     * Prepara el logo por defecto para los PDFs
     */
    private function ensureDefaultLogo() {
        $defaultLogoPath = public_path('img/logo.png');
        
        // Si no existe el logo por defecto, crear uno básico
        if (!file_exists($defaultLogoPath)) {
            // Crear una imagen de 120x80 con texto "CENTRO MÉDICO"
            $image = imagecreatetruecolor(120, 80);
            
            // Colores
            $blue = imagecolorallocate($image, 26, 59, 93);  // Color azul oscuro
            $white = imagecolorallocate($image, 255, 255, 255);
            
            // Rellenar el fondo
            imagefill($image, 0, 0, $white);
            
            // Dibujar texto
            imagestring($image, 5, 10, 30, "CENTRO MEDICO", $blue);
            
            // Guardar la imagen
            imagepng($image, $defaultLogoPath);
            imagedestroy($image);
        }
        
        return $defaultLogoPath;
    }

    /**
     * Descarga la historia clínica en formato PDF
     */
    public function download(Request $request){
        try{
            // Asegurar que exista el logo por defecto
            $defaultLogoPath = $this->ensureDefaultLogo();
            
            $especialities = Especiality::getEspecialities();
            $data = $request->all();
            $id = $data["id"];
            
            // Obtener la historia clínica con relaciones precargadas para optimizar
            $model = History::with(['patient', 'user', 'user.profile'])->findOrFail($id);
            $controls = ControlHistory::with(['user', 'user.profile'])->where("history_id","=",$id)->get();
            
            // Obtener la identidad del consultorio para pasarla a la vista del PDF
            $identity = ClinicIdentityHelper::getActiveIdentity();
            
            // Convertir la imagen a base64 para incrustación directa en el PDF
            if ($identity && $identity->logo_path) {
                $logoPath = public_path('storage/' . $identity->logo_path);
                
                // Verificar que el archivo exista
                if (!file_exists($logoPath)) {
                    $logoPath = $defaultLogoPath;
                }
                
                // Obtener tipo de imagen
                $imgInfo = getimagesize($logoPath);
                $mime = isset($imgInfo['mime']) ? $imgInfo['mime'] : 'image/png';
                
                // Leer imagen y convertir a base64
                $logoData = base64_encode(file_get_contents($logoPath));
                $identity->logo_data_uri = 'data:' . $mime . ';base64,' . $logoData;
            } else {
                // Si no hay logo, usar el predeterminado
                $logoData = base64_encode(file_get_contents($defaultLogoPath));
                if (!$identity) {
                    $identity = new \stdClass();
                }
                $identity->logo_data_uri = 'data:image/png;base64,' . $logoData;
            }
            
            // Configurar opciones del PDF para mejor calidad y presentación
            $options = [
                'paper' => 'a4',
                'orientation' => 'portrait',
                'enable_remote' => true,
                'enable_javascript' => true,
                'images' => true,
                'enable_php' => false,
                'is_html5_parser_enabled' => true,
                'dpi' => 300,
                'enable_font_subsetting' => true,
                'default_font' => 'helvetica',
                'margin_left' => 10,
                'margin_right' => 10,
                'margin_top' => 10,
                'margin_bottom' => 10,
                'margin_header' => 0,
                'margin_footer' => 5,
            ];
            
            $pdf = PDF::loadView('reports.history', [
                "model" => $model,
                "especialities" => $especialities,
                "controls" => $controls,
                "identity" => $identity
            ])->setOptions($options);
            
            // Nombre del archivo más descriptivo
            $fileName = "Historia_" . $model->number_history . "_" . 
                      $model->patient()->first()->firstname . "_" . 
                      $model->patient()->first()->lastname . ".pdf";
            
            // Sanitizar el nombre del archivo para evitar problemas con caracteres especiales
            $fileName = str_replace(' ', '_', $fileName);
            $fileName = preg_replace('/[^A-Za-z0-9_\-\.]/', '', $fileName);
            
            return $pdf->download($fileName);

        }catch(Throwable $th){
            throw new GlobalException($th->getMessage());
        }
    }


    /**
     * 
     */
    public function previewFile(Request $request)
    {
        try {
            $data = $request->all();
            $id = $data["id"];
            $model = Files::find($id);
            if($model === null)
                throw new GlobalException(__("error-500.messageNoSearch"));

            $model->path = str_replace("fileuploads/","",$model->path);    
            return view("preview-files",[
                "file"=>$model
            ]);
        } catch (Throwable $th) {
            throw new GlobalException($th->getMessage());
        }
    }

    /**
     * Guardar la configuración de historias médicas para una especialidad
     */
    public function saveConfiguration(Request $request)
    {
        try {
            DB::beginTransaction();
            $data = $request->all();
            $especialityId = $data['especiality_id'] ?? null;

            // Validar que se haya seleccionado una especialidad
            if (!$especialityId) {
                DB::rollback();
                return redirect()->back()->with('error', __('common-table.configure-history.selectEspecialityRequired'));
            }

            // Buscar o crear la configuración para la especialidad
            $configuration = HistoryConfiguration::firstOrNew(['especiality_id' => $especialityId]);
            
            // Generar ID si es nuevo
            if (!$configuration->exists) {
                $configuration->id = md5(uniqid($especialityId, true));
            }

            // Preparar datos de secciones y exámenes
            $sectionTypes = isset($data['section_types']) ? $data['section_types'] : [];
            $medicalExams = isset($data['medical_exams']) ? $data['medical_exams'] : [];

            // Validar que haya al menos una sección y un examen seleccionado
            if (empty($sectionTypes)) {
                DB::rollback();
                return redirect()->back()->with('error', __('common-table.configure-history.selectAtLeastOneAntecedent'));
            }

            if (empty($medicalExams)) {
                DB::rollback();
                return redirect()->back()->with('error', __('common-table.configure-history.selectAtLeastOneMedicalExam'));
            }

            // Guardar configuración
            $configuration->section_types = $sectionTypes;
            $configuration->medical_exams = $medicalExams;
            $configuration->save();

            DB::commit();

            return redirect()->route('/admin/configure-history', ['especiality_id' => $especialityId])->with('success', __('common-table.configure-history.saved'));

        } catch (Throwable $th) {
            DB::rollback();
            throw new GlobalException($th->getMessage());
        }
    }

    public function getHistoryConfiguration(Request $request)
    {
        try {
            $especialityId = $request->get('especiality_id');
            
            if (!$especialityId) {
                return response()->json([
                    'sections' => [],
                    'medicalExams' => []
                ]);
            }
            
            // Buscar configuración para la especialidad
            $configuration = HistoryConfiguration::where('especiality_id', $especialityId)->first();
            
            if ($configuration) {
                return response()->json([
                    'sections' => $configuration->section_types ?? [],
                    'medicalExams' => $configuration->medical_exams ?? []
                ]);
            } else {
                // No hay configuración para esta especialidad
                return response()->json([
                    'sections' => [],
                    'medicalExams' => []
                ]);
            }
        } catch (Throwable $th) {
            return response()->json([
                'error' => $th->getMessage(),
                'sections' => [],
                'medicalExams' => []
            ], 500);
        }
    }

    public function edit(Request $request){
        try{
            $data = $request->all();
            $id = trim($data["id"]);
            $sectionTypes = SectionType::all();
            $history = History::find($id);
            $physicalTest = new PhysicalTest();
            
            // Obtener la configuración si hay una especialidad seleccionada
            $configuration = null;
            if (isset($history->especiality)) {
                $configuration = HistoryConfiguration::where('especiality_id', $history->especiality)->first();
            } elseif (isset($data['especiality_id'])) {
                $configuration = HistoryConfiguration::where('especiality_id', $data['especiality_id'])->first();
            }
            
            return view("edit-history",[
                "history"=>$history,
                "sectionTypes"=>$sectionTypes,
                "patients"=>Patients::all(),
                "physicalTest"=>$physicalTest,
                "new"=>false,
                "configuration" => $configuration
            ]);
        }catch(Exception $e){
            throw new GlobalException($e->getMessage());
        }
    }

    /**
     * Vista previa del PDF de la historia clínica en el navegador
     */
    public function preview(Request $request){
        try{
            // Asegurar que exista el logo por defecto
            $defaultLogoPath = $this->ensureDefaultLogo();
            
            $especialities = Especiality::getEspecialities();
            $data = $request->all();
            $id = $data["id"];
            
            // Obtener la historia clínica con relaciones precargadas para optimizar
            $model = History::with(['patient', 'user', 'user.profile'])->findOrFail($id);
            $controls = ControlHistory::with(['user', 'user.profile'])->where("history_id","=",$id)->get();
            
            // Obtener la identidad del consultorio
            $identity = ClinicIdentityHelper::getActiveIdentity();
            
            // Convertir la imagen a base64 para incrustación directa en el PDF
            if ($identity && $identity->logo_path) {
                $logoPath = public_path('storage/' . $identity->logo_path);
                
                // Verificar que el archivo exista
                if (!file_exists($logoPath)) {
                    $logoPath = $defaultLogoPath;
                }
                
                // Obtener tipo de imagen
                $imgInfo = getimagesize($logoPath);
                $mime = isset($imgInfo['mime']) ? $imgInfo['mime'] : 'image/png';
                
                // Leer imagen y convertir a base64
                $logoData = base64_encode(file_get_contents($logoPath));
                $identity->logo_data_uri = 'data:' . $mime . ';base64,' . $logoData;
            } else {
                // Si no hay logo, usar el predeterminado
                $logoData = base64_encode(file_get_contents($defaultLogoPath));
                if (!$identity) {
                    $identity = new \stdClass();
                }
                $identity->logo_data_uri = 'data:image/png;base64,' . $logoData;
            }
            
            // Configurar opciones del PDF para mejor calidad y presentación
            $options = [
                'paper' => 'a4',
                'orientation' => 'portrait',
                'enable_remote' => true,
                'enable_javascript' => true,
                'images' => true,
                'enable_php' => false,
                'is_html5_parser_enabled' => true,
                'dpi' => 300,
                'enable_font_subsetting' => true,
                'default_font' => 'helvetica',
                'margin_left' => 10,
                'margin_right' => 10,
                'margin_top' => 10,
                'margin_bottom' => 10,
                'margin_header' => 0,
                'margin_footer' => 5,
            ];
            
            $pdf = PDF::loadView('reports.history', [
                "model" => $model,
                "especialities" => $especialities,
                "controls" => $controls,
                "identity" => $identity
            ])->setOptions($options);
            
            // Nombre más descriptivo para la vista previa en el navegador
            $previewName = "Historia_" . $model->number_history . "_" . 
                          $model->patient()->first()->firstname . "_" . 
                          $model->patient()->first()->lastname . ".pdf";

            // Devolver el PDF para visualización en el navegador
            return $pdf->stream($previewName);

        }catch(Throwable $th){
            throw new GlobalException($th->getMessage());
        }
    }
}
