<?php

namespace App\Http\Controllers\Admin\Api;

use App\Classes\Constant;
use App\Events\PatientRegistered;
use App\Http\Controllers\Controller;
use App\Models\Appointment;
use App\Models\Cart;
use App\Models\Item;
use App\Models\ItemHistory;
use App\Models\LabkitOrderItem;
use App\Models\Patient;
use App\Models\PatientNote;
use App\Models\PatientPrescription;
use App\Models\PatientRegActivity;
use App\Models\Setting;
use Carbon\Carbon;
use DateTime;
use Illuminate\Contracts\Routing\UrlGenerator;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Illuminate\Auth\Access\AuthorizationException;

use Agence104\LiveKit\VideoGrant;
use App\Events\AppointmentBooked;
use App\Events\PaymentProcessed;
use App\Models\Admin;
use App\Models\Lab;
use App\Models\LabKit;
use App\Models\LicenseNumberModel;
use App\Models\MedicalHistoryAnswer;
use App\Models\PatientPlan;
use App\Models\Plan;
use App\Models\PlanV1;
use App\Models\Prescription;
use App\Models\ProfileAnswer;
use App\Models\ProfileCategory;
use App\Models\QuestionBuilder;
use App\Models\Subscription;
use App\Models\Telemedpro;
use Carbon\CarbonTimeZone;
use DateTimeZone;
use Error;
use Exception;
use Illuminate\Support\Facades\Log;
use Yajra\DataTables\DataTables;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Validator;
use Agence104\LiveKit\AccessToken;
use Agence104\LiveKit\AccessTokenOptions;
use Agence104\LiveKit\RoomCreateOptions;
use Agence104\LiveKit\RoomServiceClient;

class PatientController extends Controller
{
    protected $url;
    protected $user;
    public function __construct(UrlGenerator $url)
    {
        $this->url = $url;
        $this->user = Auth::guard('admin')->user();
    }
    public function newPatient(Request $request)
    {
        try {
            $this->authorizeForUser($this->user, 'add', new Patient);
            $validatedData = $request->validate([
                'first_name' => 'required|string|max:255',
                'last_name' => 'required|string|max:255',
                'email' => 'required|string|email|max:255|unique:patients',
                'password' => 'required',
                'dob' => 'required|date_format:Y-m-d',
                'phone_no' => 'required'
            ]);
            $patient = Patient::create([
                'first_name' => $request->input('first_name'),
                'last_name' => $request->input('last_name'),
                'phone_no' => $request->input('phone_no'),
                'email' => $request->input('email'),
                'password' => Hash::make($request->input('password')),
                'dob' => $request->input('dob'),
                'gender' => $request->input('gender') ?? "",
            ]);

            $patient->address = $request->input('address');
            $patient->state =  $request->input('state');
            $patient->city =  $request->input('city');
            $patient->country =  $request->input('country');

            $patient->zip_code = $request->input('zip');

            $patient->shipping_address = $request->input('address');
            $patient->shipping_state =  $request->input('state');
            $patient->shipping_city =  $request->input('city');
            $patient->shipping_zipcode = $request->input('zip');


            $image = $request->get('profile_pic');
            $fileName = 'profile-' . time();

            $logo = base64_decode($image);
            $ext = (explode('/', finfo_buffer(finfo_open(), $logo, FILEINFO_MIME_TYPE))[1]);

            $imageName =  $fileName . '.' . $ext;
            Storage::disk('local')->put("public/profile_pictures/" . $imageName, $logo);
            $patient->profile_picture = $imageName;
            $patient->save();


            if ($patient->dob) {
                $birthDate = new DateTime($patient->dob);
                $today = new DateTime(date('Y-m-d'));
                $age = $today->diff($birthDate)->y;
                $patient->age = $age;
            } else {
                $patient->age = 0;
            }
            PatientRegActivity::create([
                'patient_id' => $patient->id,
                'activity' => 'patient_registered'
            ]);
            $setting = Setting::find(1);
            event(new PatientRegistered($patient, $validatedData));
            return response()
                ->json([
                    'data' => $patient
                ]);
        } catch (AuthorizationException $e) {
            return  $e->getMessage();
        }
    }
    public function patientShippingAddress($id, Request $request)
    {
        try {
            $this->authorizeForUser($this->user, 'edit', new Patient);
            $patient = Patient::find($id);
            $patient->shipping_address = $request->input('address');
            $patient->shipping_state =  $request->input('state');
            $patient->shipping_city =  $request->input('city');
            $patient->shipping_zipcode = $request->input('zip');
            $patient->save();
            return response()
                ->json([
                    'data' => $patient
                ]);
        } catch (AuthorizationException $e) {
            return  $e->getMessage();
        }
    }
    public function patientList(Request $request)
    {
        try {
            $this->authorizeForUser($this->user, 'list', new Patient);
            $patients = Patient::query();

            // Filter by state
            if ($request->input('state') != "all") {
                $patients->where('patients.state', $request->input('state'));
            }

            // Filter by gender
            if ($request->input('gender') != "all") {
                $patients->where('patients.gender', $request->input('gender'));
            }

            // Filter by plan (assuming you have a plan field or relation)
            if ($request->input('plan') != "all") {
                $planNames = $request->input('plan');

                $patients->leftJoin('patient_plan', 'patients.id', '=', 'patient_plan.patient_id')
                    ->leftJoin('plans_v1', 'patient_plan.plan_id', '=', 'plans_v1.id')
                    ->where('plans_v1.slug', $planNames);
            }

            // Join with the carts table to get order details
            $patients->leftJoin('carts', 'patients.id', '=', 'carts.patient_id')
                ->select('patients.*')
                ->addSelect([
                    'last_order_date' => Cart::selectRaw('MAX(created_at)')
                        ->whereColumn('patient_id', 'patients.id'),
                    'total_orders' => Cart::selectRaw('COUNT(*)')
                        ->whereColumn('patient_id', 'patients.id'),
                    'total_subscriptions' => Cart::selectRaw('COUNT(DISTINCT start_subscription)')
                        ->whereColumn('patient_id', 'patients.id'),
                ]);

            Log::info('PatientList Datatable:', [
                'sql' => $patients->toSql(),
                'bindings' => $patients->getBindings()
            ]);

            // Use DataTables to process the query
            return DataTables::of($patients)->make(true);
        } catch (\Exception | Error $e) {
            // Log the error
            Log::error('Error in patientList: ' . $e->getMessage());
            // Return an error response
            return response()->json([
                'error' => 'An error occurred while processing the request.',
                'message' => $e->getMessage()
            ], 500);
        }
    }
    public function patientFullDetail(Patient $patient)
    {
        try {
            $this->authorizeForUser($this->user, 'edit', new Patient);
            $patient->first_name = $patient->first_name . " " . $patient->last_name;
            $plans = PatientPlan::join('plans_v1', 'patient_plan.plan_id', '=', 'plans_v1.id')
                ->leftJoin('medication_categories', 'plans_v1.medication_category_id', '=', 'medication_categories.id')
                ->where('patient_plan.patient_id', $patient->id)
                ->select('plans_v1.*', 'medication_categories.category_name')
                ->orderBy('plans_v1.created_at', 'desc')
                ->first();
            $upcomingMeetings = Appointment::select(
                'appointments.patient_id',
                'appointments.timezone',
                'appointments.appointment_time',
                'appointments.appointment_date',
                'carts.id as order_id'
            )
                ->leftJoin("carts", "carts.appointment_id", "appointments.id")
                ->where("appointments.patient_id", $patient->id)
                // dd(Constant::getFullSql($upcomingMeetings));
                ->get();
            $completedMeetings = Appointment::select(
                'appointments.patient_id',
                'appointments.appointment_time',
                'appointments.appointment_date',
                'appointments.start_time',
                'appointments.end_time',
                'appointments.timezone',
                'telemed_pros.name as provider_name',
                'telemed_pros_id as provider_id',
                'carts.id as order_id'
            )
                ->leftJoin('telemed_pros', 'telemed_pros.id', 'appointments.telemed_pros_id')
                ->leftJoin("carts", "carts.appointment_id", "appointments.id")
                ->where("appointments.patient_id", $patient->id)
                ->where('appointments.start_time', "!=", null)
                ->where('appointments.end_time', "!=", null)
                ->get();
            $patientNotes = PatientNote::select(
                'patient_notes.id',
                'patient_notes.note',
                'patient_notes.note_type',
                'telemed_pros.name as provider_name',
                'telemed_pros.id as provider_id',
                'patient_notes.created_at',
                'patient_notes.patient_id',
                'carts.id as order_id',
                'patient_notes.created_by_id',
                'patient_notes.created_by_type'
            )
                ->leftJoin('telemed_pros', 'patient_notes.telemed_pros_id', 'telemed_pros.id')
                ->leftJoin("carts", "carts.appointment_id", "patient_notes.appointment_id")
                ->where("patient_notes.patient_id", $patient->id)
                ->get();

            foreach ($patientNotes as $notes) {
                if ($notes->note_type != 'Notes')
                    $notes->note = $this->url->to("assets/files/" . $notes->patient_id . ".png");
                else
                    $notes->note = $notes->note;
            }
            $patientPrescription = PatientPrescription::select(
                'patient_prescription.*',
                'telemed_pros.name as provider_name',
                'prescriptions.*',
                'carts.id as order_id'
            )
                ->leftJoin('appointments', 'patient_prescription.appointment_id', 'appointments.id')
                ->leftJoin("carts", "carts.appointment_id", "appointments.id")
                ->leftJoin('telemed_pros', 'appointments.telemed_pros_id', 'telemed_pros.id')
                ->leftJoin('prescriptions', 'prescriptions.id', 'patient_prescription.prescription_id')
                ->where('patient_prescription.patient_id', $patient->id)->get();
            $patient->profile_completion_Percentage = $patient->profile_completion_Percentage;
            $labkits = LabkitOrderItem::leftJoin(
                'lab_kit',
                'labkit_order_items.lab_kit_id',
                'lab_kit.id'
            )
                ->leftJoin(
                    'items',
                    'items.id',
                    'labkit_order_items.item_id'
                )
                ->leftJoin(
                    'plans_v1',
                    'plans_v1.id',
                    'items.plans_id'
                )
                ->leftJoin(
                    'carts',
                    'carts.id',
                    'labkit_order_items.cart_id'
                )
                ->where('carts.patient_id', $patient->id)
                ->select(
                    'labkit_order_items.id',
                    'labkit_order_items.status',
                    'labkit_order_items.result',
                    'lab_kit.name as lab_kit_name',
                    'plans_v1.id as product_id',
                    'plans_v1.title as product_name'
                )
                ->get();
            $orderList = Cart::select("appointments.*", 'appointments.id as appointment_id', 'carts.*', 'carts.id as order_id', 'telemed_pros.name as agent_name', 'telemed_pros.email as agent_email')
                ->leftJoin('appointments',  'appointments.id', 'carts.appointment_id')
                ->leftJoin('telemed_pros', 'appointments.telemed_pros_id', '=', 'telemed_pros.id')
                ->where('appointments.patient_id', $patient->id);

            $orderListData = $orderList->get();
            return response()->json([
                'patient' => $patient,
                'plans' => $plans,
                'upcomingMeetings' => $upcomingMeetings,
                'completed_meetings' => $completedMeetings,
                'patientNotes' => $patientNotes,
                'prescriptionData' => $patientPrescription,
                'labkit' => $labkits,
                'orderListData' => $orderListData,
            ]);
        } catch (AuthorizationException $e) {
            return  $e->getMessage();
        }
    }
    public function patientDelete(Patient $patient)
    {
        try {
            $this->authorizeForUser($this->user, 'delete', new Patient);
            Patient::where("id", $patient->id)->delete();
            return response()->json([
                'patient' => "Deleted Successfully"
            ]);
        } catch (AuthorizationException $e) {
            return  $e->getMessage();
        }
    }
    public function patientUpdate(Patient $patient, Request $request)
    {
        try {
            $this->authorizeForUser($this->user, 'edit', new Patient);
            $patient->first_name = $request->input('first_name');
            $patient->last_name = $request->input('last_name');
            $patient->phone_no = $request->input('phone_no');
            $patient->shipping_address = $request->input('gender');
            $patient->shipping_address = $request->input('dob');
            if ($request->input('password')) {
                $patient->password = Hash::make($request->input('password'));
            }
            $patient->shipping_address = $request->input('address');
            $patient->shipping_state =  $request->input('state');
            $patient->shipping_city =  $request->input('city');
            $patient->shipping_zipcode = $request->input('zip');
            $patient->shipping_country = $request->input('country');

            $patient->save();
            return response()->json([
                'message' => 'Patient updated successfully',
                'telemed' => $patient
            ]);
        } catch (AuthorizationException $e) {
            return  $e->getMessage();
        }
    }
    public function getNotePatient(Patient $patient, Appointment $appointment, Request $request)
    {
        try {
            $this->authorizeForUser($this->user, 'patient_notes', new Patient);
            $patientNotes = PatientNote::where("patient_id", $patient->id)
                ->where("appointment_id", $appointment->id)
                ->with('appointment')
                ->get();

            $data = $patientNotes->map(function ($patientNote) {
                $fileUrl = "/assets/files/{$patientNote->id}.png";
                $filePath = public_path($fileUrl);

                if (File::exists($filePath)) {
                    $fileUrl = "/assets/files/{$patientNote->id}.png";
                } else {
                    $fileUrl = null;
                }

                return [
                    'id' => $patientNote->id,
                    'note' => $patientNote->note,
                    'note_type' => $patientNote->note_type,
                    'created_at' => $patientNote->created_at,
                    'patient_id' => $patientNote->patient_id,
                    'appointment' => $patientNote->appointment,
                    'telemedPro' => $patientNote->telemedPro,
                    'file_url' => $fileUrl,
                    'telemedPro' => $patientNote->appointment?->telemedPro
                ];
            });

            return response()->json([
                'message' => 'Patient notes retrieved',
                'data' => $data
            ], 200);
        } catch (AuthorizationException $e) {
            return  $e->getMessage();
        }
    }
    public function patient(Patient $patient)
    {
        return response()->json([
            'data' => $patient
        ], 200);
    }
    public function getPatientPrescription($patient_id, $appointment_id)
    {
        try {
            $this->authorizeForUser($this->user, 'patinet_prescriptions', new Patient);
            $patientPrescription = PatientPrescription::with('prescription')
                ->where('patient_id', $patient_id)
                ->where('appointment_id', $appointment_id)
                ->get();

            $prescriptionData = [];
            foreach ($patientPrescription as $prescription) {
                $prescriptionData[] = [
                    'patient' => $prescription->patient,
                    'prescription' => $prescription->prescription,
                    'created_at' => $prescription->created_at,
                    'updated_at' => $prescription->updated_at,
                    'direction_one' => $prescription->direction_one,
                    'direction_two' => $prescription->direction_two,
                    'dont_substitute' => $prescription->dont_substitute,
                    'comments' => $prescription->comments,
                    'appointment_id' => $prescription->appointment_id,
                    'status' => $prescription->status,
                    'appointment' => $prescription->appointment,
                    'telemedPro' => $prescription->appointment->telemedPro,
                    'licenseNumber' => LicenseNumberModel::where("provider_id", $patient_id)->orderBy('id', 'DESC')->first()
                ];
            }
            if (!$patientPrescription->isEmpty()) {
                return response()->json($prescriptionData);
            } else {
                return response()->json(['message' => 'Prescription not found'], 404);
            }
        } catch (AuthorizationException $e) {
            return  $e->getMessage();
        }
    }
    public function storePatientPrescription(Request $request)
    {
        try {
            $this->authorizeForUser($this->user, 'patinet_prescriptions', new Patient);
            $cart = Cart::find($request->input("order_id"));
            $prescription = PatientPrescription::create($request->all());
            $prescription->appointment_id =    $cart->appointment_id;
            $prescription->status = "pending";
            $prescription->save();
            $patient = $prescription->patient;
            $setting = Setting::find(1);
            /* Mail::send('emails.prescriptionAdd', ['patient' => $patient, 'prescription' => $prescription, 'setting' => $setting], function ($message) use ($patient, $user) {
                $message->to($patient->email, $patient->first_name)
                    ->subject('New Prescription Details from ' . $user->name);
            }); */
            return response()->json($prescription, 200);
        } catch (AuthorizationException $e) {
            return  $e->getMessage();
        }
    }
    public function updateStatusPrescription($patient_prescription_id, Request $request)
    {
        //
        try {
            $this->authorizeForUser($this->user, 'patinet_prescriptions_edit', new Patient);
            $status = $request->input("status");
            $prescription = PatientPrescription::find($patient_prescription_id);
            $prescription->status = $status;
            $prescription->save();
            $patient = $prescription->patient;
            $setting = Setting::find(1);
            /* Mail::send('emails.prescriptionUpdated', ['patient' => $patient, 'setting' => $setting], function ($message) use ($patient) {
                $message->to($patient->email, $patient->first_name)
                    ->subject('Prescription updated.');
            }); */
            return response()->json($prescription, 200);
        } catch (AuthorizationException $e) {
            return  $e->getMessage();
        }
    }
    public function getStatusPrescription($patient_prescription_id)
    {
        $prescription = PatientPrescription::with(['prescription'])
            ->findOrFail($patient_prescription_id);
        return response()->json($prescription, 200);
    }
    public function updatePatientPrescription($id, Request $request)
    {
        try {
            $prescription = PatientPrescription::findOrFail($id);
            $prescription->update($request->all());

            if ($request->has('status')) {
                $prescription->status = $request->input('status');
            }

            $prescription->save();

            $patient = $prescription->patient;
            $setting = Setting::find(1);

            // You might want to add email notification here if needed

            return response()->json([
                'message' => 'Prescription updated successfully',
                'data' => $prescription
            ], 200);
        } catch (AuthorizationException $e) {
            return $e->getMessage();
        } catch (\Exception $e) {
            return response()->json([
                'message' => 'An error occurred while updating the prescription',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    public function deletePatientPrescription($id)
    {
        try {
            $prescription = PatientPrescription::findOrFail($id);
            $prescription->delete();

            return response()->json([
                'message' => 'Prescription deleted successfully'
            ], 200);
        } catch (AuthorizationException $e) {
            return $e->getMessage();
        } catch (\Exception $e) {
            return response()->json([
                'message' => 'An error occurred while deleting the prescription',
                'error' => $e->getMessage()
            ], 500);
        }
    }
}
