<?php

namespace App\Controllers;

use App\Models\CareRequestModel;
use App\Models\ServiceModel;
use App\Services\AuditService;
use App\Services\DispatchService;
use App\Services\PaymentService;

class Patient extends BaseController
{
    private function patientId(): int
    {
        $row=db_connect()->table('patient_profiles')->select('id')->where('user_id',auth_id())->get()->getRowArray();
        if(!$row){db_connect()->table('patient_profiles')->insert(['user_id'=>auth_id(),'created_at'=>date('Y-m-d H:i:s'),'updated_at'=>date('Y-m-d H:i:s')]); return (int)db_connect()->insertID();}
        return (int)$row['id'];
    }

    public function dashboard()
    {
        $pid=$this->patientId(); $db=db_connect();
        $stats=['upcoming'=>$db->table('care_requests')->where('patient_id',$pid)->whereIn('status',['requested','matching','offered','accepted','scheduled'])->countAllResults(),'active'=>$db->table('care_requests')->where('patient_id',$pid)->whereIn('status',['en_route','arrived','in_progress'])->countAllResults(),'followups'=>$db->table('visits')->where('patient_id',$pid)->where('follow_up_at >=',date('Y-m-d H:i:s'))->countAllResults(),'records'=>$db->table('clinical_notes')->where('patient_id',$pid)->countAllResults()];
        $visits=$db->table('care_requests cr')->select('cr.*,s.name service_name,u.full_name practitioner_name,pp.profession')->join('services s','s.id=cr.service_id')->join('practitioner_profiles pp','pp.id=cr.assigned_practitioner_id','left')->join('users u','u.id=pp.user_id','left')->where('cr.patient_id',$pid)->orderBy('cr.created_at','DESC')->limit(6)->get()->getResultArray();
        $notifications=$db->table('notifications')->where('user_id',auth_id())->orderBy('id','DESC')->limit(5)->get()->getResultArray();
        return $this->portal('patient/dashboard',['title'=>'Patient Dashboard','stats'=>$stats,'visits'=>$visits,'notifications'=>$notifications]);
    }

    public function requestForm()
    {
        return $this->portal('patient/request',['title'=>'Request Care','services'=>(new ServiceModel())->where('is_active',1)->orderBy('sort_order')->findAll(),'family'=>db_connect()->table('family_members')->where('patient_id',$this->patientId())->where('status','active')->get()->getResultArray()]);
    }

    public function submitRequest()
    {
        $rules=['service_id'=>'required|integer','address_text'=>'required|min_length[5]|max_length[255]','chief_complaint'=>'required|min_length[5]|max_length[1500]','urgency'=>'required|in_list[routine,priority]'];
        if(!$this->validate($rules)) return redirect()->back()->withInput()->with('errors',$this->validator->getErrors());
        $pid=$this->patientId(); $service=(new ServiceModel())->find((int)$this->request->getPost('service_id')); if(!$service) return redirect()->back()->with('error','Please select a valid care service.');
        $scheduled=$this->request->getPost('care_when')==='scheduled' ? $this->request->getPost('scheduled_for') : date('Y-m-d H:i:s');
        $id=(new CareRequestModel())->insert(['patient_id'=>$pid,'family_member_id'=>$this->request->getPost('family_member_id') ?: null,'service_id'=>$service['id'],'scheduled_for'=>$scheduled,'urgency'=>$this->request->getPost('urgency'),'status'=>'matching','chief_complaint'=>trim((string)$this->request->getPost('chief_complaint')),'latitude'=>$this->request->getPost('latitude') ?: null,'longitude'=>$this->request->getPost('longitude') ?: null,'address_text'=>trim((string)$this->request->getPost('address_text')),'estimated_amount'=>$service['base_price']]);
        (new PaymentService())->initiate((int)auth_id(),(int)$id,(float)$service['base_price'],'pending');
        $match=(new DispatchService())->assignBest((int)$id);
        (new AuditService())->log('care_request.created','care_request',(int)$id,['matched'=>(bool)$match]);
        return redirect()->to('/patient/visits')->with('success',$match?'Your request is being offered to a nearby verified practitioner.':'Your care request is active and our dispatch queue will continue matching it.');
    }

    public function activeVisit()
    {
        $pid=$this->patientId(); $db=db_connect();
        $visit=$db->table('care_requests cr')->select('cr.*,s.name service_name,pp.profession,u.full_name practitioner_name,u.phone practitioner_phone')
            ->join('services s','s.id=cr.service_id')->join('practitioner_profiles pp','pp.id=cr.assigned_practitioner_id','left')->join('users u','u.id=pp.user_id','left')
            ->where('cr.patient_id',$pid)->whereIn('cr.status',['accepted','scheduled','en_route','arrived','in_progress'])->orderBy('cr.updated_at','DESC')->get()->getRowArray();
        return $this->portal('patient/active_visit',['title'=>'Visit in Progress','visit'=>$visit]);
    }

    public function visits(){ return $this->generic('My Visits','Manage active, scheduled and previous home-care visits.','care_requests','created_at'); }
    public function health(){ $pid=$this->patientId();$db=db_connect();$notes=$db->table('clinical_notes')->where('patient_id',$pid)->orderBy('id','DESC')->limit(20)->get()->getResultArray();$prescriptions=$db->table('prescriptions p')->select('p.*,pi.medication_name,pi.dose,pi.frequency,pi.duration')->join('prescription_items pi','pi.prescription_id=p.id','left')->where('p.patient_id',$pid)->orderBy('p.id','DESC')->get()->getResultArray();$labs=$db->table('lab_requests')->where('patient_id',$pid)->orderBy('id','DESC')->get()->getResultArray();return $this->portal('patient/health',['title'=>'Health Records','notes'=>$notes,'prescriptions'=>$prescriptions,'labs'=>$labs]); }
    public function orderPrescription(int $prescriptionId){$pid=$this->patientId();$db=db_connect();$rx=$db->table('prescriptions')->where(['id'=>$prescriptionId,'patient_id'=>$pid,'status'=>'issued'])->get()->getRowArray();if(!$rx)return redirect()->back()->with('error','Prescription is not available for fulfilment.');$existing=$db->table('pharmacy_orders')->where('prescription_id',$prescriptionId)->whereNotIn('status',['cancelled'])->countAllResults();if($existing)return redirect()->back()->with('warning','A pharmacy order already exists for that prescription.');$partner=$db->table('partners')->select('id')->where(['type'=>'pharmacy','status'=>'active'])->orderBy('id')->get()->getRowArray();$db->table('pharmacy_orders')->insert(['prescription_id'=>$prescriptionId,'patient_id'=>$pid,'partner_id'=>$partner['id']??null,'status'=>'pending','created_at'=>date('Y-m-d H:i:s'),'updated_at'=>date('Y-m-d H:i:s')]);(new AuditService())->log('pharmacy_order.created','pharmacy_order',(int)$db->insertID());return redirect()->to('/patient/pharmacy')->with('success','Prescription sent for pharmacy fulfilment.'); }

    public function labs(){ return $this->generic('Lab Results','Home sample collection requests and released partner-lab results.','lab_requests','created_at'); }
    public function pharmacy(){ return $this->generic('Pharmacy','Prescription fulfilment and medication delivery orders.','pharmacy_orders','created_at'); }
    public function telehealth(){ return $this->generic('Video Care','Secure virtual appointments and follow-up consultations.','appointments','created_at'); }
    public function packages(){ $rows=[]; try{$rows=db_connect()->table('care_packages')->where('is_active',1)->orderBy('price')->get()->getResultArray();}catch(\Throwable $e){} return $this->portal('patient/packages',['title'=>'Care Packages','rows'=>$rows]); }
    public function subscribePackage(int $id){$pid=$this->patientId();$db=db_connect();$package=$db->table('care_packages')->where(['id'=>$id,'is_active'=>1])->get()->getRowArray();if(!$package)return redirect()->back()->with('error','Care package not found.');$existing=$db->table('subscriptions')->where(['patient_id'=>$pid,'care_package_id'=>$id,'status'=>'active'])->countAllResults();if($existing)return redirect()->back()->with('warning','You already have this active care package.');$starts=date('Y-m-d H:i:s');$renews=$package['billing_period']==='monthly'?date('Y-m-d H:i:s',strtotime('+1 month')):($package['billing_period']==='quarterly'?date('Y-m-d H:i:s',strtotime('+3 months')):null);$db->table('subscriptions')->insert(['patient_id'=>$pid,'care_package_id'=>$id,'status'=>'active','starts_at'=>$starts,'renews_at'=>$renews,'created_at'=>$starts,'updated_at'=>$starts]);(new PaymentService())->initiate((int)auth_id(),null,(float)$package['price'],'pending');(new AuditService())->log('care_package.subscribed','care_package',$id);return redirect()->to('/patient/payments')->with('success','Care package activated and payment created.'); }

    public function family(){ $rows=db_connect()->table('family_members')->where('patient_id',$this->patientId())->where('status','active')->orderBy('id','DESC')->get()->getResultArray(); return $this->portal('patient/family',['title'=>'Family Profiles','rows'=>$rows]); }
    public function addFamilyMember(){ $rules=['full_name'=>'required|min_length[2]|max_length[120]','relationship'=>'required|max_length[50]','date_of_birth'=>'permit_empty|valid_date[Y-m-d]','gender'=>'permit_empty|max_length[30]']; if(!$this->validate($rules))return redirect()->back()->withInput()->with('errors',$this->validator->getErrors()); db_connect()->table('family_members')->insert(['patient_id'=>$this->patientId(),'full_name'=>trim((string)$this->request->getPost('full_name')),'relationship'=>trim((string)$this->request->getPost('relationship')),'date_of_birth'=>$this->request->getPost('date_of_birth') ?: null,'gender'=>$this->request->getPost('gender') ?: null,'status'=>'active','created_at'=>date('Y-m-d H:i:s'),'updated_at'=>date('Y-m-d H:i:s')]); (new AuditService())->log('family_member.created','family_member',(int)db_connect()->insertID()); return redirect()->back()->with('success','Family profile added.'); }
    public function archiveFamilyMember(int $id){ db_connect()->table('family_members')->where(['id'=>$id,'patient_id'=>$this->patientId()])->update(['status'=>'archived','updated_at'=>date('Y-m-d H:i:s')]); (new AuditService())->log('family_member.archived','family_member',$id); return redirect()->back()->with('success','Family profile archived.'); }
    public function payments(){ return $this->generic('Payments','Review invoices, payment status and receipts.','payments','created_at','user_id',auth_id()); }
    public function messages(){ $db=db_connect();$rows=$db->table('messages')->groupStart()->where('sender_user_id',auth_id())->orWhere('recipient_user_id',auth_id())->groupEnd()->orderBy('created_at','DESC')->limit(100)->get()->getResultArray();return $this->portal('portal/page',['title'=>'Messages','heading'=>'Messages','intro'=>'Secure care conversations with practitioners and TibaLeta support.','rows'=>$rows]); }
    public function notifications(){ return $this->generic('Notifications','Care updates, reminders and account notices.','notifications','created_at','user_id',auth_id()); }
    public function profile(){ $db=db_connect();$profile=$db->table('patient_profiles')->where('id',$this->patientId())->get()->getRowArray();$user=$db->table('users')->where('id',auth_id())->get()->getRowArray();return $this->portal('patient/profile',['title'=>'Profile & Settings','profile'=>$profile,'user'=>$user]); }
    public function updateProfile(){ $rules=['full_name'=>'required|min_length[2]|max_length[120]','phone'=>'permit_empty|max_length[30]','date_of_birth'=>'permit_empty|valid_date[Y-m-d]','gender'=>'permit_empty|max_length[30]','blood_group'=>'permit_empty|max_length[10]','emergency_contact_name'=>'permit_empty|max_length[120]','emergency_contact_phone'=>'permit_empty|max_length[30]'];if(!$this->validate($rules))return redirect()->back()->withInput()->with('errors',$this->validator->getErrors());$db=db_connect();$db->transStart();$db->table('users')->where('id',auth_id())->update(['full_name'=>trim((string)$this->request->getPost('full_name')),'phone'=>trim((string)$this->request->getPost('phone')),'updated_at'=>date('Y-m-d H:i:s')]);$db->table('patient_profiles')->where('id',$this->patientId())->update(['date_of_birth'=>$this->request->getPost('date_of_birth')?:null,'gender'=>$this->request->getPost('gender')?:null,'blood_group'=>$this->request->getPost('blood_group')?:null,'emergency_contact_name'=>$this->request->getPost('emergency_contact_name')?:null,'emergency_contact_phone'=>$this->request->getPost('emergency_contact_phone')?:null,'preferred_language'=>$this->request->getPost('preferred_language')?:'English','updated_at'=>date('Y-m-d H:i:s')]);$db->transComplete();$auth=$this->session->get('auth_user');$auth['full_name']=trim((string)$this->request->getPost('full_name'));$this->session->set('auth_user',$auth);(new AuditService())->log('patient.profile.updated','patient',$this->patientId());return redirect()->back()->with('success','Profile updated.'); }

    private function generic(string $title,string $intro,string $table,string $order,string $field='patient_id',$value=null)
    {
        $value=$value ?? $this->patientId(); $rows=[];
        try{$rows=db_connect()->table($table)->where($field,$value)->orderBy($order,'DESC')->limit(50)->get()->getResultArray();}catch(\Throwable $e){}
        return $this->portal('portal/page',['title'=>$title,'heading'=>$title,'intro'=>$intro,'rows'=>$rows]);
    }
}
