<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Symfony\Component\HttpFoundation\Response;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\File;  // Add this import
use App\Models\Device;
use App\Models\Patient; 
use App\Models\NearLab;  
use App\Services\QrCodeService;
use App\Mail\ActivationPatientMail;
use App\Services\TwilioService;
use App\Models\PatientECG; 
use App\Models\PatientVitals;
use App\Http\Responses\ApiResponse;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\DB;

class PatientapiController extends Controller
{
    protected $qrCodeService;
    protected $twilioService;
  public function __construct(TwilioService $twilioService, QrCodeService $qrCodeService)
    {
        $this->twilioService = $twilioService;
        $this->qrCodeService = $qrCodeService;    
    }
    
public function receiveFile(Request $request)
    {
        try {
            // Validate inputs based on the JSON structure
            $request->validate([
                'patient_id' => 'required|integer|exists:patient,patient_id', // Updated table name to 'patient'
                'device_info' => 'required|array',
                'device_info.device_id' => 'required|string|max:255',
                'device_info.location' => 'nullable|string|max:255',
                'device_info.device_status' => 'nullable|string',
                'device_info.firmware_version' => 'nullable|string|max:50',
                'device_info.hardware_version' => 'nullable|string|max:50',
                'device_info.ip_address' => 'nullable|ip',
                'device_info.last_heartbeat' => 'nullable|date_format:Y-m-d\TH:i:s\Z',
                'vitals' => 'required|array',
                'vitals.pulse_rate_spo2' => 'nullable|integer|min:0',
                'vitals.pulse_rate_nibp' => 'nullable|integer|min:0', 
                'vitals.ecg_heart_rate' => 'nullable|integer|min:0',
                'vitals.respiration_rate' => 'nullable|integer|min:0',
                'vitals.blood_oxygen' => 'nullable|integer|between:0,100',
                'vitals.weight_kg' => 'nullable|numeric|min:0',
                'vitals.height_cm' => 'nullable|numeric|min:0',
                'vitals.bmi' => 'nullable|numeric|min:0',
                'vitals.blood_glucose' => 'required|array',
                'vitals.blood_glucose.fasting' => 'nullable|integer|min:0',
                'vitals.blood_glucose.pre_meal' => 'nullable|integer|min:0',
                'vitals.blood_glucose.post_meal' => 'nullable|integer|min:0',
                'blood_pressure' => 'required|array',
                'blood_pressure.systolic' => 'nullable|integer|min:0',
                'blood_pressure.diastolic' => 'nullable|integer|min:0',
                'temperature' => 'required|array',
                'temperature.temp_1_c' => 'nullable|numeric|min:0',
                'temperature.temp_2_c' => 'nullable|numeric|min:0',
                'temperature.ir_temp_c' => 'nullable|numeric|min:0',
                'spo2_status' => 'nullable|array',
                'spo2_status.finger_off' => 'nullable|boolean',
                'spo2_status.pulse_flag' => 'nullable|boolean',
                'spo2_status.search_pulse' => 'nullable|boolean',
                'spo2_status.sensor_off' => 'nullable|boolean',
                'spo2_status.bar_graph' => 'nullable|integer|min:0',
                'ecg_five_lead' => 'nullable|array',
                'ecg_five_lead.leads' => 'nullable|array',
                'ecg_five_lead.pace_flag' => 'nullable|boolean',
                'ecg_five_lead.heartbeat_flag' => 'nullable|boolean',
                'ecg_five_lead.lead_status' => 'nullable|array',
                'ecg_twelve_lead' => 'nullable|array',
                'ecg_twelve_lead.leads' => 'nullable|array',
                'ecg_twelve_lead.pace_flag' => 'nullable|boolean',
                'ecg_twelve_lead.heartbeat_flag' => 'nullable|boolean',
                'ecg_twelve_lead.lead_status' => 'nullable|array',
                'ecg_twelve_lead.saturation' => 'nullable|array',
            ]);

            // Use a database transaction to ensure atomicity
            return DB::transaction(function () use ($request) {
                // Calculate BMI if not provided
                $weight = $request->input('vitals.weight_kg');
                $height = $request->input('vitals.height_cm');
                $bmi = $request->input('vitals.bmi');
                if (empty($bmi) && !empty($weight) && !empty($height) && $height > 0) {
                    $heightInMeters = $height / 100;
                    $bmi = round($weight / ($heightInMeters * $heightInMeters), 2);
                }

                // Prepare data for PatientVitals
            $vitalsData = [
                'patient_id' => $request->input('patient_id'),
                'body_temperature' => $request->input('temperature.temp_1_c') ?? $request->input('temperature.temp_2_c') ?? $request->input('temperature.ir_temp_c'),
                'pulse_rate' => $request->input('vitals.pulse_rate_spo2') ?? $request->input('vitals.pulse_rate_nibp') ?? $request->input('vitals.ecg_heart_rate'),
                'respiration_rate' => $request->input('vitals.respiration_rate'),
                'blood_pressure_systolic' => $request->input('blood_pressure.systolic'),
                'blood_pressure_diastolic' => $request->input('blood_pressure.diastolic'),
                'blood_oxygen' => $request->input('vitals.blood_oxygen'),
                'weight' => $weight,
                'height' => $height,
                'bmi' => $bmi,
                'blood_glucose_level' => $request->input('vitals.blood_glucose.post_meal') ?? $request->input('vitals.blood_glucose.pre_meal') ?? $request->input('vitals.blood_glucose.fasting'),
                'blood_glucose_fasting' => $request->input('vitals.blood_glucose'),
                'temperature' => $request->input('temperature'),
                'spo2_status' => $request->input('spo2_status'),
                'pulse_rate_spo2' => $request->input('vitals.pulse_rate_spo2'),
                'pulse_rate_nibp' => $request->input('vitals.pulse_rate_nibp'),
                'ecg_heart_rate' => $request->input('vitals.ecg_heart_rate'),
                'created_at' => Carbon::parse($request->input('timestamp')),
            ];
                // Create PatientVitals record
                $patientVitals = PatientVitals::create($vitalsData);

                // Prepare data for Device
                $deviceData = [
                    'device_id' => $request->input('device_info.device_id'),
                    'serial_number' => $request->input('device_info.device_id'),
                    'ip_address' => $request->input('device_info.ip_address'),
                    'device_status' => $request->input('device_info.device_status'),
                    'firmware_version' => $request->input('device_info.firmware_version'),
                    'hardware_version' => $request->input('device_info.hardware_version'),
                    'location' => $request->input('device_info.location'),
                    'last_heartbeat' => $request->input('device_info.last_heartbeat'),
                ];
  
                // Update or create Device record
                Device::updateOrCreate(
                    ['device_id' => $deviceData['device_id']],
                    $deviceData
                );

               // Handle ECG data
                $ecg_five_lead = $request->input('ecg_five_lead');
                $ecg_twelve_lead = $request->input('ecg_twelve_lead');
                
                // Check if either ECG field is present in the request
                if ($request->has('ecg_five_lead') || $request->has('ecg_twelve_lead')) {
                    $ecgData = [
                        'vitals_id' => $patientVitals->vital_id,
                        'ecg_five_lead' => $ecg_five_lead ?: null, // Use null if empty
                        'ecg_twelve_lead' => $ecg_twelve_lead ?: null, // Use null if empty
                    ];

                    $ecg = PatientECG::create($ecgData);
                    Log::info('PatientECG created.', [
                        'ecg_id' => $ecg->id,
                        'vitals_id' => $patientVitals->vital_id,
                        'ecg_five_lead' => $ecgData['ecg_five_lead'],
                        'ecg_twelve_lead' => $ecgData['ecg_twelve_lead'],
                    ]);
                } else {
                    Log::warning('No ECG data provided in request.', [
                        'ecg_five_lead' => $ecg_five_lead,
                        'ecg_twelve_lead' => $ecg_twelve_lead,
                    ]);
                }

                Log::info('Data successfully uploaded.', [
                    'vitals_id' => $patientVitals->vital_id,
                    'patient_id' => $patientVitals->patient_id,
                    'device_id' => $deviceData['device_id'],
                ]);  
                return ApiResponse::success('The data has been successfully processed and saved to the database.', $patientVitals);
            });

        } catch (ValidationException $e) {
            Log::error('Validation error while saving data.', [
                'errors' => $e->errors(),
                'request_data' => $request->all(),
            ]);

            return ApiResponse::error('Validation failed.', $e->errors(), 422);

        } catch (\Exception $e) {
            Log::error('Error while saving data.', [
                'error' => $e->getMessage(),
                'request_data' => $request->all(),
            ]);

            return ApiResponse::error('Failed to upload data.', $e->getMessage(), 500);
        }
    }  
   
    public function getAllPatientVitals()
{
    try {
        $vitals = PatientVitals::where('patient_id', 2830)->orderBy('patient_id', 'desc')->get(); // fallback to 'id' sorting

        if ($vitals->isEmpty()) { 
            return ApiResponse::error('No vitals found in the database.', null, 404);
        }

        return ApiResponse::success('All patient vitals retrieved successfully.', $vitals);

    } catch (\Exception $e) {
        return ApiResponse::error('Failed to retrieve patient vitals.', $e->getMessage(), 500);
    }
}
 
public function uploadImage(Request $request)
{
    $fieldFolderMap = [
        'photo' => 'hcpImage',
        'image' => 'hcpImage',
        'aadhar_card' => 'documents',
        'pan_card' => 'documents',
        'drivers_license' => 'documents',
        'insurance_card' => 'documents',
        'document_image' => 'hcp_edu_document',
        'lic_document_image' => 'hcp_lic_document'
    ];

    foreach ($fieldFolderMap as $field => $folder) {
        if ($request->hasFile($field)) {
            $file = $request->file($field);
            $fileName = time() . '_' . $file->getClientOriginalName();

            $file->storeAs($folder, $fileName, 'public');

            return response()->json([
                'status' => true,
                'filename' => $fileName,
                'url' => asset("storage/$folder/" . $fileName),
            ]);
        }
    }

    return response()->json(['status' => false, 'message' => 'No valid file uploaded'], 400);
}  
      
  


  
public function ecgData(Request $request)
{
    try {
        // Simulated ECG Data (Replace this with actual device data)
        $ecgData = [
            ["timestamp_ms" => 0, "LeadII" => 2013, "LeadI" => 2177, "LeadV" => 2109, "PaceFlag" => 0, "HeartBeatFlag" => 0, "Checksum" => 99],
            ["timestamp_ms" => 2, "LeadII" => 1815, "LeadI" => 1750, "LeadV" => 2026, "PaceFlag" => 0, "HeartBeatFlag" => 0, "Checksum" => 40],
            ["timestamp_ms" => 4, "LeadII" => 1939, "LeadI" => 2336, "LeadV" => 1776, "PaceFlag" => 0, "HeartBeatFlag" => 0, "Checksum" => 78],
            ["timestamp_ms" => 6, "LeadII" => 2032, "LeadI" => 1931, "LeadV" => 2137, "PaceFlag" => 0, "HeartBeatFlag" => 0, "Checksum" => 47],
            ["timestamp_ms" => 8, "LeadII" => 2303, "LeadI" => 2009, "LeadV" => 2275, "PaceFlag" => 0, "HeartBeatFlag" => 0, "Checksum" => 199],
            ["timestamp_ms" => 10, "LeadII" => 2320, "LeadI" => 2213, "LeadV" => 1815, "PaceFlag" => 0, "HeartBeatFlag" => 0, "Checksum" => 161]
        ];

        // Function to add random noise
        function addRandomNoise($value, $minNoise = -10, $maxNoise = 10)
        {
            return $value + rand($minNoise, $maxNoise);
        }

        // Apply noise to each ECG data point
        foreach ($ecgData as &$data) {
            $data['LeadII'] = addRandomNoise($data['LeadII']);
            $data['LeadI'] = addRandomNoise($data['LeadI']);
            $data['LeadV'] = addRandomNoise($data['LeadV']);
        }

        return response()->json($ecgData); // ? Return ECG dataset with noise
    } catch (\Exception $e) {
        Log::error('Error while fetching ECG data', [
            'error' => $e->getMessage(),
            'request_data' => $request->all() ?? 'No data'
        ]);
        return response()->json(['error' => 'Failed to fetch ECG data'], 500);
    }
}
   


public function devices(Request $request)
{
    try {
        $rules = [
            'mac_address' => 'required|string|max:255',
            'device_id' => 'required|string|max:255',
            'serial_number' => 'required|string|max:255',
            'module_number' => 'nullable|string|max:255',
            'gps_location' => 'nullable|string|max:255',
            'local_ip_address' => 'nullable|ip',
            'status' => 'required|string|max:50',
            'company_name' => 'nullable|string|max:255',
            'firmware_version' => 'nullable|string|max:50',
            'device_uptime' => 'nullable|string|max:255',
            'battery_status' => 'nullable|string|max:50',
            'network_type' => 'nullable|string|max:50',
            'signal_strength' => 'nullable|string|max:50',
            'time_synced' => 'nullable|date_format:Y-m-d H:i:s',
        ];

        $validator = \Validator::make($request->all(), $rules);

        if ($validator->fails()) {
            return ApiResponse::error('Validation failed.', $validator->errors(), 422);
        }

        $data = $request->all();

        $existingDevice = Device::where('mac_address', $data['mac_address'])
                                ->Where('device_id', $data['device_id'])
                                ->Where('serial_number', $data['serial_number'])
                                ->first();

        if ($existingDevice) {
            $existingDevice->update($data); 

            Log::info('Device updated successfully', ['device_id' => $existingDevice->device_id]);

            return ApiResponse::success('Device Updated Successfully.', $existingDevice);
        }

        $device = Device::create($data);

        Log::info('Device created successfully', ['device_id' => $device->device_id]);

        return ApiResponse::success('Device Registered Successfully.', $device);

    } catch (\Exception $e) {
        Log::error('Error while creating or updating device data.', [
            'error' => $e->getMessage(),
            'request_data' => $request->all() ?? 'No data'
        ]);
        return ApiResponse::error('Failed to process the device data.', $e->getMessage(), 500);
    }
}



public function patientLogin(Request $request)
{
    try {
        $request->validate([
            'payload' => 'nullable',
        ]);

        if (!$request->payload) {
            return ApiResponse::error('Please provide phone or Aadhaar number.', null, 422);
        }

        $payload = $request->payload; // e.g., "91-3726-8582-7258"
        $cleanedPayload = str_replace('-', '', $payload); // e.g., "91372685827258" (only for abha_number)

        $query = Patient::query();

        // patient_id and aadhar_card_num stored WITH dashes
        $query->where('patient_id', $payload)
              ->orWhere('aadhar_card_num', $payload)
              // abha_number stored WITHOUT dashes, so match cleaned payload
              ->orWhere('abha_number', $cleanedPayload);

        $patient = $query->first();

        if (!$patient) {
            return ApiResponse::error('No patient found with the provided details.', null, 404);
        }

        $patientDetails = Patient::selectRaw("
                CONCAT(first_name, ' ', NULLIF(last_name, '')) as full_name, 
                date_of_birth, 
                sex, 
                DATE_PART('year', AGE(date_of_birth)) as age
            ")
            ->where('patient_id', $patient->patient_id)
            ->first();

        $otp = rand(100000, 999999);
        $phone = $patient->patient_phone_num_country_code . '' . $patient->patient_phone_number;

        $this->twilioService->sendOtpViaSms($phone, $otp);
        $patientDetails['otp'] = $otp;
        $patientDetails['phone'] = $phone;

        Log::info('Patient Data Retrieved', ['patient' => $patientDetails]);

        return ApiResponse::success('Patient Data Retrieved.', $patientDetails);

    } catch (\Exception $e) {
        Log::error('Error while retrieving patient data', [
            'error' => $e->getMessage(),
        ]);
        return ApiResponse::error('Failed to retrieve patient data.', $e->getMessage(), 500);
    }
}
         






public function nearLabs()
{
    try {
    
        $labs = NearLab::all(['name', 'address', 'phone', 'email', 'latitude', 'longitude', 'icon_url']);
   
        Log::info('Near Labs Data Retrieved', ['labs' => $labs]);

        return response()->json($labs);

    } catch (\Exception $e) {

        Log::error('Error while retrieving Near labs data', [
            'error' => $e->getMessage(),
        ]);
        return response()->json([
            'error' => 'Failed to retrieve Near labs data',
            'message' => $e->getMessage()
        ], 500);
    }
}

public function patientCreate(Request $request)
{  
    $rules = [
        'first_name' => 'required|string|max:50', 
        'sex' => 'required|string|max:10',
        'address' => 'required|string',
        'patient_phone_number' => 'nullable|string|max:20',
        'email' => 'required',
        'consent_to_contact' => 'nullable|boolean',
        'consent_to_treatment' => 'nullable|boolean',
        'date_of_birth' => 'nullable|date', // ??? ???? ??? ??? ????? ?? ?? valid ??
    ];

    if ($request->filled('aadhar_card_num')) {
        $rules['aadhar_card_num'] = 'numeric|unique:patient,aadhar_card_num';
    }

    try {
        // ? ???? ?? validation errors ?? ??????
        $validatedData = $request->validate($rules);

        $patient = new Patient();
        $patient->fill($validatedData);
        $patient->patient_phone_num_country_code = $request->patient_phone_num_country_code;

        // Unique ID only if both values exist
        if ($request->filled('patient_phone_number') && $request->filled('aadhar_card_num')) {
            $patient->unique_id = $request->patient_phone_number .'.'. $request->aadhar_card_num;
        }

        // Handle Photo Upload
        if ($request->hasFile('profile_photo')) {
            $patient->photo = $this->uploadPhoto($request->file('profile_photo'));
        } 
        
        
            if ($request->hasFile('aadhar_photo')) {   
                $file = $request->file('aadhar_photo');
                   $fileName = time() . '_' . uniqid() . '.' . $file->getClientOriginalExtension();
                $file->storeAs('documents', $fileName, 'public');
                $patient->aadhar_card = $fileName;
            } 

        $patient->email = $request->email;
        // ? Default values
        $patient->date_of_birth = $request->input('date_of_birth', Carbon::now()->toDateString());
        $patient->consent_to_contact = $request->input('consent_to_contact', false);
        $patient->consent_to_treatment = $request->input('consent_to_treatment', false);
         $patient->last_name = $request->input('last_name', false);
         
         
         
         
          $qr_text = '';

            $qr_text = "Patient Information:\n";
            $qr_text .= "--------------------------\n\n";

            if ($request->first_name) {
                $qr_text .= "First Name: " . $request->first_name . "\n\n";
            }
          
            if ($request->date_of_birth) {
                $qr_text .= "Date of Birth: " . $request->input('date_of_birth', Carbon::now()->toDateString()) . "\n\n";
            }
            if ($request->sex) {
                $qr_text .= "Sex: " . $request->sex . "\n\n";
            }
            if ($request->address) {
                $qr_text .= "Address: " . $request->address . "\n\n";
            }
              if ($request->email) {
                $qr_text .= "Email: " . $request->email . "\n\n";   
            }
            if ($request->patient_phone_num_country_code) {
                $qr_text .= "Phone Country Code: " . $request->patient_phone_num_country_code . "\n\n";
            }
            if ($request->patient_phone_number) {
                $qr_text .= "Phone Number: " . $request->patient_phone_number . "\n\n";
            }
           
            if ($request->aadhar_card_num) {
                $qr_text .= "Aadhar Card: " . $request->aadhar_card_num . "\n\n";
            }

            if ($request->unique_id) {
                $qr_text .= "Unique ID: " . $request->patient_phone_number .'.'. $request->aadhar_card_num . "\n\n";
            }
 
            $qr_text .= "--------------------------\n";

            $filename = 'qr_code_' . time();
            $dataUri = $this->qrCodeService->saveQrCode($qr_text, $filename);
            $qrCode =  explode('/', $dataUri);
            if (isset($qrCode[1])) {
                $patient->qr_code = $qrCode[1];
            }
            
               $patient->save();  
               $patient->patient_id  = $patient->patient_id;  
             $data = [
               'title' => 'Activation Link',
                'body' => 'This is Bluai Patient Activation Link: ' . url('/activation/' . $patient->patient_id),
             ];
             Mail::to($request->email)->send(new ActivationPatientMail($data));  
            
       

        Log::info('Patient data successfully saved.', ['data' => $patient]);
        

        return ApiResponse::success('Patient registered successfully.', $patient);
    } catch (ValidationException $e) {
        // ? ?? validation errors return ?????
        return response()->json([
            'status' => 'error',
            'message' => 'Validation failed.',
            'errors' => $e->errors() // ??? validation errors return ?????
        ], 422);
    } catch (\Exception $e) {
        Log::error('Error while saving patient data.', [
            'error' => $e->getMessage(),
            'request_data' => $request->all()
        ]);

        return ApiResponse::error('Failed to register patient.', $e->getMessage(), 500);
    }
}


/**
 * Handle Photo Upload
 */
private function uploadPhoto($file)
{
        $fileName = time() . '_' . uniqid() . '.' . $file->getClientOriginalExtension();
    $file->storeAs('photos', $fileName, 'public');
    
    
    return $fileName;
} 
 


 
}

?>