<?php

namespace App\Controllers;

use App\Services\AuditService;
use App\Services\ClinicalService;
use App\Services\NotificationService;

class Practitioner extends BaseController
{
    private function profile(): array
    {
        $row=db_connect()->table('practitioner_profiles')->where('user_id',auth_id())->get()->getRowArray();
        if(!$row) throw new \RuntimeException('Practitioner profile is missing.');
        return $row;
    }

    public function dashboard()
    {
        $p=$this->profile(); $db=db_connect();
        $stats=['today'=>$db->table('visits')->where('practitioner_id',$p['id'])->where('DATE(created_at)',date('Y-m-d'))->countAllResults(),'requests'=>$db->table('care_request_assignments')->where(['practitioner_id'=>$p['id'],'status'=>'offered'])->countAllResults(),'earnings'=>$db->table('payouts')->selectSum('net_amount')->where('practitioner_id',$p['id'])->where('status','paid')->get()->getRow('net_amount') ?: 0,'rating'=>$p['rating'] ?: 0];
        $requests=$db->table('care_request_assignments a')->select('a.*,cr.address_text,cr.chief_complaint,cr.urgency,cr.scheduled_for,s.name service_name')->join('care_requests cr','cr.id=a.care_request_id')->join('services s','s.id=cr.service_id')->where(['a.practitioner_id'=>$p['id'],'a.status'=>'offered'])->orderBy('a.offered_at','DESC')->limit(5)->get()->getResultArray();
        $schedule=$db->table('care_requests cr')->select('cr.*,s.name service_name')->join('services s','s.id=cr.service_id')->where('cr.assigned_practitioner_id',$p['id'])->whereIn('cr.status',['accepted','scheduled','en_route','arrived','in_progress'])->orderBy('cr.scheduled_for')->limit(8)->get()->getResultArray();
        return $this->portal('practitioner/dashboard',['title'=>'Practitioner Dashboard','profile'=>$p,'stats'=>$stats,'requests'=>$requests,'schedule'=>$schedule],'practitioner');
    }

    public function requests(){ $p=$this->profile(); $rows=db_connect()->table('care_request_assignments a')->select('a.*,cr.address_text,cr.chief_complaint,cr.status request_status,s.name service_name')->join('care_requests cr','cr.id=a.care_request_id')->join('services s','s.id=cr.service_id')->where('a.practitioner_id',$p['id'])->orderBy('a.id','DESC')->limit(50)->get()->getResultArray(); return $this->portal('portal/page',['title'=>'Care Requests','heading'=>'Care Requests','intro'=>'Review suitable nearby requests offered by TibaLeta dispatch.','rows'=>$rows],'practitioner'); }

    public function respond(int $assignmentId,string $decision)
    {
        if(!in_array($decision,['accept','decline'],true)) return redirect()->back();
        $p=$this->profile(); $db=db_connect(); $a=$db->table('care_request_assignments')->where(['id'=>$assignmentId,'practitioner_id'=>$p['id'],'status'=>'offered'])->get()->getRowArray(); if(!$a) return redirect()->back()->with('error','That request is no longer available.');
        $db->transStart();
        if($decision==='accept'){$db->table('care_request_assignments')->where('id',$assignmentId)->update(['status'=>'accepted','responded_at'=>date('Y-m-d H:i:s'),'updated_at'=>date('Y-m-d H:i:s')]);$db->table('care_requests')->where('id',$a['care_request_id'])->update(['status'=>'accepted','assigned_practitioner_id'=>$p['id'],'accepted_at'=>date('Y-m-d H:i:s'),'updated_at'=>date('Y-m-d H:i:s')]);$cr=$db->table('care_requests')->where('id',$a['care_request_id'])->get()->getRowArray();$existingVisit=$db->table('visits')->where('care_request_id',$a['care_request_id'])->countAllResults();if(!$existingVisit)$db->table('visits')->insert(['care_request_id'=>$a['care_request_id'],'patient_id'=>$cr['patient_id'],'practitioner_id'=>$p['id'],'status'=>'scheduled','created_at'=>date('Y-m-d H:i:s'),'updated_at'=>date('Y-m-d H:i:s')]);$patient=$db->table('patient_profiles')->where('id',$cr['patient_id'])->get()->getRowArray(); if($patient)(new NotificationService())->sendCareUpdate((int)$patient['user_id'],'A practitioner accepted your care request.','/patient/visits');}
        else {$db->table('care_request_assignments')->where('id',$assignmentId)->update(['status'=>'declined','responded_at'=>date('Y-m-d H:i:s'),'updated_at'=>date('Y-m-d H:i:s')]);}
        $db->transComplete(); (new AuditService())->log('care_request.'.$decision,'care_request',(int)$a['care_request_id']);
        return redirect()->back()->with('success',$decision==='accept'?'Care request accepted.':'Request declined and returned to dispatch.');
    }

    public function toggleOnline(){ $p=$this->profile(); $new=$p['is_online']?0:1; db_connect()->table('practitioner_profiles')->where('id',$p['id'])->update(['is_online'=>$new,'updated_at'=>date('Y-m-d H:i:s')]); return redirect()->back()->with('success',$new?'You are now available for care requests.':'You are now offline.'); }
    public function visitDetail(int $requestId)
    {
        $p=$this->profile(); $db=db_connect();
        $visit=$db->table('care_requests cr')->select('cr.*,s.name service_name,ppat.user_id patient_user_id,u.full_name patient_name,v.id visit_id')
            ->join('services s','s.id=cr.service_id')->join('patient_profiles ppat','ppat.id=cr.patient_id')->join('users u','u.id=ppat.user_id')->join('visits v','v.care_request_id=cr.id','left')
            ->where(['cr.id'=>$requestId,'cr.assigned_practitioner_id'=>$p['id']])->get()->getRowArray();
        if(!$visit) throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        $notes=$db->table('clinical_notes')->where(['patient_id'=>$visit['patient_id'],'practitioner_id'=>$p['id']])->orderBy('id','DESC')->limit(5)->get()->getResultArray();
        return $this->portal('practitioner/visit',['title'=>'Care Visit','visit'=>$visit,'notes'=>$notes],'practitioner');
    }

    public function updateVisitStatus(int $requestId)
    {
        $next=(string)$this->request->getPost('status'); $allowed=['en_route','arrived','in_progress','completed']; if(!in_array($next,$allowed,true))return redirect()->back()->with('error','Invalid visit status.');
        $p=$this->profile(); $db=db_connect(); $cr=$db->table('care_requests')->where(['id'=>$requestId,'assigned_practitioner_id'=>$p['id']])->get()->getRowArray(); if(!$cr)return redirect()->back()->with('error','Visit not found.');
        $transitions=['accepted'=>['en_route'],'scheduled'=>['en_route'],'en_route'=>['arrived'],'arrived'=>['in_progress'],'in_progress'=>['completed']]; if(!in_array($next,$transitions[$cr['status']] ?? [],true))return redirect()->back()->with('error','That visit transition is not allowed.');
        $db->transStart(); $updates=['status'=>$next,'updated_at'=>date('Y-m-d H:i:s')]; if($next==='completed'){$updates['completed_at']=date('Y-m-d H:i:s');}
        $db->table('care_requests')->where('id',$requestId)->update($updates);
        $v=$db->table('visits')->where('care_request_id',$requestId)->get()->getRowArray();
        if(!$v){$db->table('visits')->insert(['care_request_id'=>$requestId,'patient_id'=>$cr['patient_id'],'practitioner_id'=>$p['id'],'status'=>$next,'started_at'=>$next==='in_progress'?date('Y-m-d H:i:s'):null,'arrived_at'=>$next==='arrived'?date('Y-m-d H:i:s'):null,'completed_at'=>$next==='completed'?date('Y-m-d H:i:s'):null,'created_at'=>date('Y-m-d H:i:s'),'updated_at'=>date('Y-m-d H:i:s')]);}
        else {$vu=['status'=>$next,'updated_at'=>date('Y-m-d H:i:s')]; if($next==='arrived')$vu['arrived_at']=date('Y-m-d H:i:s');if($next==='in_progress')$vu['started_at']=date('Y-m-d H:i:s');if($next==='completed')$vu['completed_at']=date('Y-m-d H:i:s');$db->table('visits')->where('id',$v['id'])->update($vu);}
        $patient=$db->table('patient_profiles')->where('id',$cr['patient_id'])->get()->getRowArray(); if($patient)(new NotificationService())->sendCareUpdate((int)$patient['user_id'],'Your visit is now '.str_replace('_',' ',$next).'.','/patient/visits/active');
        $db->transComplete(); (new AuditService())->log('visit.status.'.$next,'care_request',$requestId);
        return redirect()->to('/practitioner/visits/'.$requestId)->with('success','Visit status updated.');
    }

    public function createPrescription(int $requestId)
    {
        $rules=['medication_name'=>'required|max_length[180]','dose'=>'permit_empty|max_length[100]','frequency'=>'permit_empty|max_length[100]','duration'=>'permit_empty|max_length[100]','instructions'=>'permit_empty|max_length[1000]'];
        if(!$this->validate($rules)) return redirect()->back()->with('errors',$this->validator->getErrors());
        $p=$this->profile();$db=db_connect();$cr=$db->table('care_requests')->where(['id'=>$requestId,'assigned_practitioner_id'=>$p['id']])->get()->getRowArray();if(!$cr)return redirect()->back()->with('error','Visit not found.');$v=$db->table('visits')->where('care_request_id',$requestId)->get()->getRowArray();if(!$v)return redirect()->back()->with('error','Start the visit before issuing a prescription.');
        $db->transStart();$db->table('prescriptions')->insert(['visit_id'=>$v['id'],'patient_id'=>$cr['patient_id'],'practitioner_id'=>$p['id'],'status'=>'issued','instructions'=>$this->request->getPost('instructions'),'issued_at'=>date('Y-m-d H:i:s'),'created_at'=>date('Y-m-d H:i:s'),'updated_at'=>date('Y-m-d H:i:s')]);$rx=(int)$db->insertID();$db->table('prescription_items')->insert(['prescription_id'=>$rx,'medication_name'=>trim((string)$this->request->getPost('medication_name')),'dose'=>$this->request->getPost('dose')?:null,'frequency'=>$this->request->getPost('frequency')?:null,'duration'=>$this->request->getPost('duration')?:null,'instructions'=>$this->request->getPost('instructions')?:null,'created_at'=>date('Y-m-d H:i:s'),'updated_at'=>date('Y-m-d H:i:s')]);$db->transComplete();(new AuditService())->log('prescription.issued','prescription',$rx,['visit_id'=>$v['id']]);return redirect()->back()->with('success','Prescription issued to the patient record.');
    }

    public function createLabRequest(int $requestId)
    {
        $rules=['tests'=>'required|max_length[2000]','collection_type'=>'required|in_list[home,facility]'];if(!$this->validate($rules))return redirect()->back()->with('errors',$this->validator->getErrors());$p=$this->profile();$db=db_connect();$cr=$db->table('care_requests')->where(['id'=>$requestId,'assigned_practitioner_id'=>$p['id']])->get()->getRowArray();if(!$cr)return redirect()->back()->with('error','Visit not found.');$v=$db->table('visits')->where('care_request_id',$requestId)->get()->getRowArray();if(!$v)return redirect()->back()->with('error','Start the visit before requesting laboratory tests.');$partner=$db->table('partners')->select('id')->where(['type'=>'lab','status'=>'active'])->orderBy('id')->get()->getRowArray();$db->table('lab_requests')->insert(['visit_id'=>$v['id'],'patient_id'=>$cr['patient_id'],'practitioner_id'=>$p['id'],'partner_id'=>$partner['id']??null,'tests'=>trim((string)$this->request->getPost('tests')),'collection_type'=>$this->request->getPost('collection_type'),'status'=>'requested','requested_at'=>date('Y-m-d H:i:s'),'created_at'=>date('Y-m-d H:i:s'),'updated_at'=>date('Y-m-d H:i:s')]);$id=(int)$db->insertID();(new AuditService())->log('lab_request.created','lab_request',$id,['visit_id'=>$v['id']]);return redirect()->back()->with('success','Lab request created and routed to an available partner.');
    }

    public function saveClinicalNote(int $requestId)
    {
        $rules=['subjective'=>'permit_empty|max_length[5000]','objective'=>'permit_empty|max_length[5000]','assessment'=>'required|max_length[5000]','plan'=>'required|max_length[5000]'];
        if(!$this->validate($rules)) return redirect()->back()->with('errors',$this->validator->getErrors());
        $p=$this->profile(); $db=db_connect(); $cr=$db->table('care_requests')->where(['id'=>$requestId,'assigned_practitioner_id'=>$p['id']])->get()->getRowArray(); if(!$cr)return redirect()->back()->with('error','Visit not found.');
        $v=$db->table('visits')->where('care_request_id',$requestId)->get()->getRowArray(); if(!$v)return redirect()->back()->with('error','Start the visit before adding clinical notes.');
        (new ClinicalService())->recordEncounter((int)$v['id'],(int)$cr['patient_id'],(int)$p['id'],$this->request->getPost());
        return redirect()->back()->with('success','Clinical note saved to the encounter.');
    }

    public function visits(){ return $this->generic('Visits','Manage accepted, active and completed home-care visits.','visits'); }
    public function patients(){ return $this->generic('Patients','Patients you have treated through TibaLeta.','visits'); }
    public function records(){ return $this->generic('Clinical Notes','Secure documentation from your encounters.','clinical_notes'); }
    public function prescriptions(){ return $this->generic('Prescriptions','Create and review prescriptions linked to patient encounters.','prescriptions'); }
    public function labs(){ return $this->generic('Lab Requests','Request home or partner laboratory tests and review results.','lab_requests'); }
    public function telehealth(){ return $this->generic('Video Care','Scheduled virtual consultations and follow-up sessions.','appointments'); }
    public function earnings(){ return $this->generic('Earnings & Payouts','Track completed visit earnings, platform fees and payouts.','payouts'); }
    public function availability(){ return $this->generic('Availability','Control when and where you are available to receive home-care requests.','practitioner_availability'); }
    public function profilePage(){ $p=$this->profile();$db=db_connect();$user=$db->table('users')->where('id',auth_id())->get()->getRowArray();$credentials=$db->table('practitioner_credentials')->where('practitioner_id',$p['id'])->orderBy('id','DESC')->get()->getResultArray();return $this->portal('practitioner/profile',['title'=>'Professional Profile','profile'=>$p,'user'=>$user,'credentials'=>$credentials],'practitioner'); }
    public function updateProfile(){ $rules=['profession'=>'required|max_length[120]','bio'=>'permit_empty|max_length[5000]','registration_number'=>'permit_empty|max_length[100]','professional_body'=>'permit_empty|max_length[150]','years_experience'=>'permit_empty|integer|greater_than_equal_to[0]','service_radius_km'=>'permit_empty|decimal|greater_than[0]'];if(!$this->validate($rules))return redirect()->back()->withInput()->with('errors',$this->validator->getErrors());$p=$this->profile();db_connect()->table('practitioner_profiles')->where('id',$p['id'])->update(['profession'=>trim((string)$this->request->getPost('profession')),'bio'=>trim((string)$this->request->getPost('bio')),'registration_number'=>trim((string)$this->request->getPost('registration_number')) ?: null,'professional_body'=>trim((string)$this->request->getPost('professional_body')) ?: null,'years_experience'=>(int)$this->request->getPost('years_experience'),'service_radius_km'=>(float)$this->request->getPost('service_radius_km'),'verification_status'=>$p['verification_status']==='verified'?'in_review':$p['verification_status'],'updated_at'=>date('Y-m-d H:i:s')]);(new AuditService())->log('practitioner.profile.updated','practitioner',(int)$p['id']);return redirect()->back()->with('success','Professional profile updated. Material changes may require re-verification.'); }
    public function addCredential(){ $p=$this->profile();$rules=['credential_type'=>'required|max_length[100]','credential_number'=>'permit_empty|max_length[120]','issuer'=>'permit_empty|max_length[150]','expires_at'=>'permit_empty|valid_date[Y-m-d]'];if(!$this->validate($rules))return redirect()->back()->withInput()->with('errors',$this->validator->getErrors());$file=$this->request->getFile('document');$path=null;if($file && $file->isValid() && !$file->hasMoved()){if($file->getSize()>5*1024*1024)return redirect()->back()->with('error','Credential document must be 5 MB or smaller.');$ext=strtolower($file->getExtension());if(!in_array($ext,['pdf','jpg','jpeg','png'],true))return redirect()->back()->with('error','Upload a PDF, JPG or PNG credential document.');$mime=$file->getMimeType();if(!in_array($mime,['application/pdf','image/jpeg','image/png'],true))return redirect()->back()->with('error','The credential file type could not be verified.');$name=$file->getRandomName();$file->move(WRITEPATH.'uploads/credentials',$name);$path='credentials/'.$name;}db_connect()->table('practitioner_credentials')->insert(['practitioner_id'=>$p['id'],'credential_type'=>trim((string)$this->request->getPost('credential_type')),'credential_number'=>trim((string)$this->request->getPost('credential_number')) ?: null,'issuer'=>trim((string)$this->request->getPost('issuer')) ?: null,'document_path'=>$path,'expires_at'=>$this->request->getPost('expires_at') ?: null,'status'=>'pending','created_at'=>date('Y-m-d H:i:s'),'updated_at'=>date('Y-m-d H:i:s')]);(new AuditService())->log('practitioner.credential.submitted','credential',(int)db_connect()->insertID());return redirect()->back()->with('success','Credential submitted for review.'); }

    private function generic(string $title,string $intro,string $table)
    {
        $p=$this->profile(); $field=in_array($table,['payouts','visits','clinical_notes','prescriptions','lab_requests'],true)?'practitioner_id':'practitioner_id';
        $rows=[]; try{$rows=db_connect()->table($table)->where($field,$p['id'])->orderBy('id','DESC')->limit(50)->get()->getResultArray();}catch(\Throwable $e){}
        return $this->portal('portal/page',['title'=>$title,'heading'=>$title,'intro'=>$intro,'rows'=>$rows],'practitioner');
    }
}
