<?php
namespace App\Controllers;

use App\Traits\PatchValidationTrait;
use App\Traits\ResponseTrait;
use App\Controllers\BaseController;
use App\Models\PatVisit\PatVisitModel;
use App\Models\PatVisit\PatVisitADTModel;
use App\Models\Patient\PatientModel;

class PatVisitController extends BaseController {
	use ResponseTrait;
	use PatchValidationTrait;
	
	protected $model;

	public function __construct() {	
		$this->model = new PatVisitModel();
	}

	public function index() {
		try {
			$InternalPID = $this->request->getVar('InternalPID');
			$PVID = $this->request->getVar('PVID');
			$PatientID = $this->request->getVar('PatientID');
			$PatientName = $this->request->getVar('PatientName');
			$CreateDateFrom = $this->request->getVar('CreateDateFrom');
			$CreateDateTo = $this->request->getVar('CreateDateTo');
			
			$builder = $this->model->select('patvisit.*, patient.NameFirst, patient.NameLast, patient.PatientID, location.LocFull as LastLocation')
				->join('patient', 'patient.InternalPID=patvisit.InternalPID', 'left')
				->join('(SELECT a1.*
					FROM patvisitadt a1
					INNER JOIN (
						SELECT InternalPVID, MAX(PVADTID) AS MaxID
						FROM patvisitadt
						GROUP BY InternalPVID
					) a2 ON a1.InternalPVID = a2.InternalPVID AND a1.PVADTID = a2.MaxID
				) AS latest_patvisitadt', 'latest_patvisitadt.InternalPVID = patvisit.InternalPVID', 'left')
				->join('location', 'location.LocationID = latest_patvisitadt.LocationID', 'left');
			
			if ($InternalPID) {
				$builder->where('patvisit.InternalPID', $InternalPID);
			}
			if ($PVID) {
				$builder->like('patvisit.PVID', $PVID, 'both');
			}
			if ($PatientID) {
				$builder->like('patient.PatientID', $PatientID, 'both');
			}
			if ($PatientName) {
				$builder->groupStart()
					->like('patient.NameFirst', $PatientName, 'both')
					->orLike('patient.NameLast', $PatientName, 'both')
					->groupEnd();
			}
			if ($CreateDateFrom) {
				$builder->where('patvisit.CreateDate >=', $CreateDateFrom);
			}
			if ($CreateDateTo) {
				$builder->where('patvisit.CreateDate <=', $CreateDateTo);
			}
			
			$rows = $builder->orderBy('patvisit.CreateDate', 'DESC')->findAll();
			
			if (empty($rows)) {
				return $this->respond(['status' => 'success', 'message' => 'data not found', 'data' => []], 200);
			}
			
			return $this->respond(['status' => 'success', 'message' => 'data found', 'data' => $rows], 200);
		} catch (\Exception $e) {
			return $this->failServerError('Something went wrong: ' . $e->getMessage());
		}
	}

	public function show($PVID = null) {
		try {
			$row = $this->model->show($PVID);
			if (empty($row)) { 
				return $this->respond([ 'status' => 'success', 'message'=> "data not found", 'data' => [] ], 200); 
			} 
			return $this->respond([ 'status' => 'success', 'message'=> "data found", 'data' => $row ], 200);
		} catch (\Exception $e) {
			return $this->failServerError('Something went wrong '.$e->getMessage());
		}
	}

	public function showByPatient($InternalPID = null) {
		try {
			$rows = $this->model->showByPatient($InternalPID);
			if($rows == []) { $message = "data not found"; } 
			else { $message = "data found"; }
			return $this->respond(['status' => 'success', 'message'=> $message, 'data' => $rows ], 200);
		} catch (\Exception $e) {
			return $this->failServerError('Something went wrong '.$e->getMessage());
		}
	}

	public function update($InternalPVID = null) {
		$input = $this->requirePatchPayload($this->request->getJSON(true));
		if ($input === null) {
			return;
		}

		$id = $this->requirePatchId($InternalPVID, 'InternalPVID');
		if ($id === null) {
			return;
		}

		$visit = $this->model->find($id);
		if (!$visit) {
			return $this->respond(['status' => 'failed', 'message' => 'Visit not found', 'data' => []], 404);
		}
		$input['InternalPVID'] = $id;
		try {
			$data = $this->model->updatePatVisit($input);
			return $this->respond(['status'  => 'success', 'message' => 'Data updated successfully', 'data' => $data], 200);
		} catch (\Exception $e) {
			return $this->failServerError('Something went wrong: ' . $e->getMessage());
		}
	}

	public function create() {
		$input = $this->request->getJSON(true);
		try {
			// Validate required fields
			if (!isset($input['InternalPID']) || !is_numeric($input['InternalPID'])) {
				return $this->respond(['status' => 'error', 'message' => 'InternalPID is required and must be numeric'], 400);
			}
			
			// Check if patient exists
			$patientModel = new PatientModel();
			$patient = $patientModel->find($input['InternalPID']);
			if (!$patient) {
				return $this->respond(['status' => 'error', 'message' => 'Patient not found'], 404);
			}
			
			$data = $this->model->createPatVisit($input);
			return $this->respond(['status'  => 'success', 'message' => 'Data created successfully', 'data' => $data], 201);
		} catch (\Exception $e) {
			return $this->failServerError('Something went wrong: ' . $e->getMessage());
		}
	}

	public function delete() {
		$input = $this->request->getJSON(true);
		try {
			if (!isset($input["InternalPVID"]) || !is_numeric($input["InternalPVID"])) { 
				return $this->respond(['status' => 'error', 'message' => 'Invalid or missing ID'], 400); 
			}
			
			// Check if visit exists
			$visit = $this->model->find($input["InternalPVID"]);
			if (!$visit) {
				return $this->respond(['status' => 'error', 'message' => 'Visit not found'], 404);
			}
			
			// Soft delete using EndDate (configured in model)
			$result = $this->model->delete($input["InternalPVID"]);
			
			if ($result) {
				return $this->respond(['status' => 'success', 'message' => 'Data deleted successfully'], 200);
			} else {
				return $this->respond(['status' => 'error', 'message' => 'Failed to delete data'], 500);
			}
		} catch (\Exception $e) {
			return $this->failServerError('Something went wrong: ' . $e->getMessage());
		}
	}

	public function createADT() {
		$input = $this->request->getJSON(true);
		$internalPVID = $input['InternalPVID'] ?? $input['InternalPID'] ?? null;
		if (!$internalPVID || !is_numeric($internalPVID)) {
			return $this->respond(['status' => 'error', 'message' => 'Invalid or missing InternalPVID'], 400);
		}
		$input['InternalPVID'] = (int) $internalPVID;
		$modelPVA = new PatVisitADTModel();
		try {
			$data = $modelPVA->insert($input, true);
			$record = $modelPVA->find($data);
			if ($record) {
				$record['ADTID'] = $record['PVADTID'];
			}
			return $this->respond(['status'  => 'success', 'message' => 'Data created successfully', 'data' => $record ?? ['ADTID' => $data]], 201);
		} catch (\Exception $e) {
			return $this->failServerError('Something went wrong: ' . $e->getMessage());
		}
	}

	public function updateADT($PVADTID = null) {
		$input = $this->requirePatchPayload($this->request->getJSON(true));
		if ($input === null) {
			return;
		}

		$id = $this->requirePatchId($PVADTID, 'PVADTID');
		if ($id === null) {
			return;
		}

		$modelPVA = new PatVisitADTModel();
		$adt = $modelPVA->find($id);
		if (!$adt) {
			return $this->respond(['status' => 'failed', 'message' => 'ADT record not found', 'data' => []], 404);
		}

		$internalPVID = null;
		if (array_key_exists('InternalPVID', $adt) && !empty($adt['InternalPVID'])) {
			$internalPVID = $adt['InternalPVID'];
		} elseif (array_key_exists('InternalPID', $adt) && !empty($adt['InternalPID'])) {
			$internalPVID = $adt['InternalPID'];
		}

		if ($internalPVID !== null && (!array_key_exists('InternalPVID', $input) || $input['InternalPVID'] === null || $input['InternalPVID'] === '')) {
			$input['InternalPVID'] = $internalPVID;
		}

		$input['PVADTID'] = $id;
		try {
			$data = $modelPVA->update($id, $input);
			return $this->respond(['status'  => 'success', 'message' => 'Data updated successfully', 'data' => $data], 200);
		} catch (\Exception $e) {
			return $this->failServerError('Something went wrong: ' . $e->getMessage());
		}
	}

	public function getADTByVisit($InternalPVID = null) {
		try {
			if (!$InternalPVID || !is_numeric($InternalPVID)) {
				return $this->respond(['status' => 'error', 'message' => 'Invalid or missing InternalPVID'], 400);
			}

			$modelPVA = new PatVisitADTModel();
			$rows = $modelPVA->select('patvisitadt.*, location.LocFull as LocationName, 
				attDoc.NameFirst as AttDocFirstName, attDoc.NameLast as AttDocLastName,
				refDoc.NameFirst as RefDocFirstName, refDoc.NameLast as RefDocLastName,
				admDoc.NameFirst as AdmDocFirstName, admDoc.NameLast as AdmDocLastName,
				cnsDoc.NameFirst as CnsDocFirstName, cnsDoc.NameLast as CnsDocLastName')
				->join('location', 'location.LocationID = patvisitadt.LocationID', 'left')
				->join('contact attDoc', 'attDoc.ContactID = patvisitadt.AttDoc', 'left')
				->join('contact refDoc', 'refDoc.ContactID = patvisitadt.RefDoc', 'left')
				->join('contact admDoc', 'admDoc.ContactID = patvisitadt.AdmDoc', 'left')
				->join('contact cnsDoc', 'cnsDoc.ContactID = patvisitadt.CnsDoc', 'left')
				->where('patvisitadt.InternalPVID', $InternalPVID)
				->where('patvisitadt.DelDate', null)
				->orderBy('patvisitadt.CreateDate', 'ASC')
				->findAll();

			if (empty($rows)) {
				return $this->respond(['status' => 'success', 'message' => 'No ADT history found', 'data' => []], 200);
			}

			return $this->respond(['status' => 'success', 'message' => 'ADT history retrieved', 'data' => $rows], 200);
		} catch (\Exception $e) {
			return $this->failServerError('Something went wrong: ' . $e->getMessage());
		}
	}

	public function showADT($PVADTID = null) {
		try {
			if (!$PVADTID || !is_numeric($PVADTID)) {
				return $this->respond(['status' => 'error', 'message' => 'Invalid or missing PVADTID'], 400);
			}

			$modelPVA = new PatVisitADTModel();
			$row = $modelPVA->select('patvisitadt.*, location.LocFull as LocationName, 
				attDoc.NameFirst as AttDocFirstName, attDoc.NameLast as AttDocLastName,
				refDoc.NameFirst as RefDocFirstName, refDoc.NameLast as RefDocLastName,
				admDoc.NameFirst as AdmDocFirstName, admDoc.NameLast as AdmDocLastName,
				cnsDoc.NameFirst as CnsDocFirstName, cnsDoc.NameLast as CnsDocLastName')
				->join('location', 'location.LocationID = patvisitadt.LocationID', 'left')
				->join('contact attDoc', 'attDoc.ContactID = patvisitadt.AttDoc', 'left')
				->join('contact refDoc', 'refDoc.ContactID = patvisitadt.RefDoc', 'left')
				->join('contact admDoc', 'admDoc.ContactID = patvisitadt.AdmDoc', 'left')
				->join('contact cnsDoc', 'cnsDoc.ContactID = patvisitadt.CnsDoc', 'left')
				->where('patvisitadt.PVADTID', $PVADTID)
				->where('patvisitadt.DelDate', null)
				->first();

			if (empty($row)) {
				return $this->respond(['status' => 'success', 'message' => 'ADT record not found', 'data' => []], 200);
			}

			return $this->respond(['status' => 'success', 'message' => 'ADT record retrieved', 'data' => $row], 200);
		} catch (\Exception $e) {
			return $this->failServerError('Something went wrong: ' . $e->getMessage());
		}
	}

public function deleteADT() {
		$input = $this->request->getJSON(true);
		try {
			if (!isset($input["PVADTID"]) || !is_numeric($input["PVADTID"])) { 
				return $this->respond(['status' => 'error', 'message' => 'Invalid or missing PVADTID'], 400); 
			}
			
			$modelPVA = new PatVisitADTModel();
			$adt = $modelPVA->find($input["PVADTID"]);
			if (!$adt) {
				return $this->respond(['status' => 'error', 'message' => 'ADT record not found'], 404);
			}
			
			$result = $modelPVA->delete($input["PVADTID"]);
			
			if ($result) {
				return $this->respond(['status' => 'success', 'message' => 'ADT record deleted successfully'], 200);
			} else {
				return $this->respond(['status' => 'error', 'message' => 'Failed to delete ADT record'], 500);
			}
		} catch (\Exception $e) {
			return $this->failServerError('Something went wrong: ' . $e->getMessage());
		}
	}
}
