<?php

declare(strict_types=1);
require dirname(__DIR__) . '/app/bootstrap.php';
require_once DENTAL_ROOT . '/app/inventory_integrity.php';
header('Content-Type: application/json; charset=utf-8');

function lookup_reply(int $status,array $payload): never
{
    http_response_code($status);
    echo json_encode($payload,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
    exit;
}

if(!current_user())lookup_reply(401,['ok'=>false,'results'=>[],'message'=>'Your session has expired. Sign in again.']);
$role=active_role();
$type=trim((string)($_GET['type']??''));
$financeTypes=['invoice','insurance_coverage'];
$adminTypes=['dentist'];
$inventoryManagementTypes=['inventory_supplier','inventory_issue'];
$inventoryClinicalTypes=['inventory_item','inventory_lot','procedure','encounter'];
$sterilizationTypes=['staff','instrument_set','sterilization_equipment'];
if(in_array($type,$financeTypes,true)){
    if(!has_role(['super_admin','clinic_admin','cashier','staff']))lookup_reply(403,['ok'=>false,'results'=>[],'message'=>'The active role cannot search financial records.']);
}elseif(in_array($type,$adminTypes,true)){
    if(!has_role(['super_admin','clinic_admin']))lookup_reply(403,['ok'=>false,'results'=>[],'message'=>'The active role cannot manage Dentist assignments.']);
}elseif(in_array($type,$inventoryManagementTypes,true)){
    if(!has_role(['super_admin','clinic_admin','inventory_officer']))lookup_reply(403,['ok'=>false,'results'=>[],'message'=>'Supplier and inventory document lookup belongs to Inventory or Administration.']);
    if(!inventory_schema_ready())lookup_reply(503,['ok'=>false,'results'=>[],'message'=>'The inventory database update is pending.']);
}elseif(in_array($type,$inventoryClinicalTypes,true)){
    if(!has_role(['super_admin','clinic_admin','inventory_officer','dentist','dental_assistant']))lookup_reply(403,['ok'=>false,'results'=>[],'message'=>'The active role cannot search controlled clinical-material records.']);
    if(!inventory_schema_ready())lookup_reply(503,['ok'=>false,'results'=>[],'message'=>'The inventory database update is pending.']);
}elseif(in_array($type,$sterilizationTypes,true)){
    if(!has_role(['super_admin','clinic_admin','inventory_officer','dentist','dental_assistant']))lookup_reply(403,['ok'=>false,'results'=>[],'message'=>'The active role cannot search sterilization support records.']);
    if(!inventory_schema_ready())lookup_reply(503,['ok'=>false,'results'=>[],'message'=>'The inventory and sterilization database update is pending.']);
}else{
    lookup_reply(422,['ok'=>false,'results'=>[],'message'=>'Unsupported lookup type.']);
}

try{
    $q=trim((string)($_GET['q']??''));
    if(mb_strlen($q)<2)lookup_reply(200,['ok'=>true,'results'=>[],'message'=>'Type at least two characters.']);
    $limit=max(5,min(30,(int)($_GET['limit']??15)));
    $requestedBranch=max(0,(int)($_GET['branch_id']??0));
    $userBranch=in_array($type,$financeTypes,true)||in_array($type,$adminTypes,true)?signed_user_branch_id():inventory_user_branch_id();
    if(!has_role('super_admin')){
        if($requestedBranch>0&&$userBranch>0&&$requestedBranch!==$userBranch)lookup_reply(403,['ok'=>false,'results'=>[],'message'=>'That branch is outside your assignment.']);
        $branchId=$userBranch;
    }else{$branchId=$requestedBranch;}
    $pdo=db();$like='%'.$q.'%';$rows=[];

    switch($type){
        case 'inventory_item':
            $stockSelect=$branchId>0?',COALESCE(bs.current_stock,0) branch_stock,COALESCE(bs.reorder_level,i.reorder_level,0) branch_reorder':' ,COALESCE(i.current_stock,0) branch_stock,COALESCE(i.reorder_level,0) branch_reorder';
            $sql='SELECT i.id,i.sku,i.barcode,i.name,i.category,i.unit,i.status'.$stockSelect.' FROM `' . table('inventory_items') . '` i';
            $args=[];
            if($branchId>0){$sql.=' LEFT JOIN `' . table('inventory_branch_stocks') . '` bs ON bs.item_id=i.id AND bs.branch_id=?';$args[]=$branchId;}
            $sql.=' WHERE i.status="active" AND (i.sku LIKE ? OR i.barcode LIKE ? OR i.name LIKE ? OR i.category LIKE ?)';
            array_push($args,$like,$like,$like,$like);
            if($branchId>0&&schema_column_exists(table('inventory_items'),'branch_id')){$sql.=' AND (i.branch_id=? OR i.branch_id IS NULL)';$args[]=$branchId;}
            $sql.=' ORDER BY i.name LIMIT '.$limit;$stmt=$pdo->prepare($sql);$stmt->execute($args);
            foreach($stmt->fetchAll() as $row)$rows[]=['id'=>(int)$row['id'],'label'=>(string)$row['sku'].' · '.(string)$row['name'],'meta'=>trim((string)($row['category']??'').' · stock '.(string)$row['branch_stock'].' '.(string)($row['unit']??''),' ·'),'sku'=>(string)$row['sku'],'barcode'=>(string)($row['barcode']??''),'name'=>(string)$row['name'],'unit'=>(string)$row['unit'],'stock'=>(float)$row['branch_stock'],'reorder_level'=>(float)$row['branch_reorder']];
            break;
        case 'inventory_lot':
            if($branchId<=0)throw new RuntimeException('Choose a branch before searching inventory lots.');
            $itemId=max(0,(int)($_GET['item_id']??0));
            $sql='SELECT l.id,l.item_id,l.lot_number,l.quantity_remaining,l.expiry_date,l.status,i.sku,i.name,i.unit FROM `' . table('inventory_lots') . '` l JOIN `' . table('inventory_items') . '` i ON i.id=l.item_id WHERE l.branch_id=? AND l.status="active" AND l.quantity_remaining>0 AND (l.expiry_date IS NULL OR l.expiry_date>=CURDATE())';
            $args=[$branchId];
            if($itemId>0){$sql.=' AND l.item_id=?';$args[]=$itemId;}
            $sql.=' AND (l.lot_number LIKE ? OR i.sku LIKE ? OR i.barcode LIKE ? OR i.name LIKE ?) ORDER BY l.expiry_date IS NULL,l.expiry_date,l.received_at,l.id LIMIT '.$limit;
            array_push($args,$like,$like,$like,$like);$stmt=$pdo->prepare($sql);$stmt->execute($args);
            foreach($stmt->fetchAll() as $row)$rows[]=['id'=>(int)$row['id'],'item_id'=>(int)$row['item_id'],'label'=>(string)$row['sku'].' · lot '.(string)$row['lot_number'],'meta'=>(string)$row['name'].' · '.(string)$row['quantity_remaining'].' '.(string)$row['unit'].($row['expiry_date']?' · expires '.(string)$row['expiry_date']:' · no expiry'),'lot_number'=>(string)$row['lot_number'],'quantity_remaining'=>(float)$row['quantity_remaining'],'expiry_date'=>(string)($row['expiry_date']??''),'unit'=>(string)$row['unit']];
            break;
        case 'inventory_supplier':
            $stmt=$pdo->prepare('SELECT id,name,contact_person,phone FROM `' . table('inventory_suppliers') . '` WHERE status="active" AND (name LIKE ? OR contact_person LIKE ? OR phone LIKE ?) ORDER BY name LIMIT '.$limit);$stmt->execute([$like,$like,$like]);
            foreach($stmt->fetchAll() as $row)$rows[]=['id'=>(int)$row['id'],'label'=>(string)$row['name'],'meta'=>trim((string)($row['contact_person']??'').' · '.(string)($row['phone']??''),' ·')];
            break;
        case 'staff':
            $sql='SELECT u.id,u.name,r.name role_name,b.name branch_name FROM `' . table('users') . '` u JOIN `' . table('roles') . '` r ON r.id=u.role_id LEFT JOIN `' . table('branches') . '` b ON b.id=u.branch_id WHERE u.status="active" AND r.code NOT IN ("patient","guardian") AND (u.name LIKE ? OR u.email LIKE ? OR r.name LIKE ?)';$args=[$like,$like,$like];
            if($branchId>0){$sql.=' AND (u.branch_id=? OR u.branch_id IS NULL)';$args[]=$branchId;}$sql.=' ORDER BY u.name LIMIT '.$limit;$stmt=$pdo->prepare($sql);$stmt->execute($args);
            foreach($stmt->fetchAll() as $row)$rows[]=['id'=>(int)$row['id'],'label'=>(string)$row['name'],'meta'=>(string)$row['role_name'].($row['branch_name']?' · '.(string)$row['branch_name']:' · all branches')];
            break;
        case 'dentist':
            $sql='SELECT u.id,u.name,b.name branch_name FROM `' . table('users') . '` u JOIN `' . table('roles') . '` r ON r.id=u.role_id LEFT JOIN `' . table('branches') . '` b ON b.id=u.branch_id WHERE u.status="active" AND r.code="dentist" AND (u.name LIKE ? OR u.email LIKE ? OR b.name LIKE ?)';$args=[$like,$like,$like];
            if($branchId>0){$sql.=' AND (u.branch_id=? OR u.branch_id IS NULL)';$args[]=$branchId;}$sql.=' ORDER BY u.name LIMIT '.$limit;$stmt=$pdo->prepare($sql);$stmt->execute($args);
            foreach($stmt->fetchAll() as $row)$rows[]=['id'=>(int)$row['id'],'label'=>(string)$row['name'],'meta'=>$row['branch_name']?(string)$row['branch_name']:'All branches'];
            break;
        case 'procedure':
            if($branchId<=0)throw new RuntimeException('Choose a branch before searching procedures.');
            $branchExpr=inventory_procedure_branch_expression();$encounterId=max(0,(int)($_GET['encounter_id']??0));
            $sql='SELECT pr.id,pr.encounter_id,pr.patient_id,pr.procedure_name,pr.tooth_region,pr.status,p.patient_no,p.first_name,p.last_name FROM `' . table('procedures') . '` pr LEFT JOIN `' . table('clinical_encounters') . '` ce ON ce.id=pr.encounter_id JOIN `' . table('patients') . '` p ON p.id=pr.patient_id WHERE '.$branchExpr.'=? AND pr.status IN ("in_progress","completed")';$args=[$branchId];
            if($encounterId>0){$sql.=' AND pr.encounter_id=?';$args[]=$encounterId;}
            $sql.=' AND (pr.procedure_name LIKE ? OR pr.tooth_region LIKE ? OR p.patient_no LIKE ? OR p.first_name LIKE ? OR p.last_name LIKE ?) ORDER BY pr.created_at DESC LIMIT '.$limit;array_push($args,$like,$like,$like,$like,$like);$stmt=$pdo->prepare($sql);$stmt->execute($args);
            foreach($stmt->fetchAll() as $row)$rows[]=['id'=>(int)$row['id'],'encounter_id'=>(int)$row['encounter_id'],'patient_id'=>(int)$row['patient_id'],'label'=>(string)$row['patient_no'].' · '.(string)$row['last_name'].', '.(string)$row['first_name'],'meta'=>(string)$row['procedure_name'].($row['tooth_region']?' · '.(string)$row['tooth_region']:'').' · '.ucwords(str_replace('_',' ',(string)$row['status']))];
            break;
        case 'encounter':
            if($branchId<=0)throw new RuntimeException('Choose a branch before searching encounters.');
            $stmt=$pdo->prepare('SELECT c.id,c.patient_id,c.status,c.created_at,c.dentist_user_id,c.dentist_name,c.assistant_user_id,c.assistant_name,p.patient_no,p.first_name,p.last_name,q.chair_id,ch.chair_name chair_name FROM `' . table('clinical_encounters') . '` c JOIN `' . table('patients') . '` p ON p.id=c.patient_id LEFT JOIN `' . table('queue_entries') . '` q ON q.id=c.queue_entry_id LEFT JOIN `' . table('clinic_chairs') . '` ch ON ch.id=q.chair_id WHERE c.branch_id=? AND c.status IN ("draft","pending_review") AND (p.patient_no LIKE ? OR p.first_name LIKE ? OR p.last_name LIKE ? OR c.dentist_name LIKE ? OR c.assistant_name LIKE ?) ORDER BY c.created_at DESC LIMIT '.$limit);$stmt->execute([$branchId,$like,$like,$like,$like,$like]);
            foreach($stmt->fetchAll() as $row)$rows[]=['id'=>(int)$row['id'],'patient_id'=>(int)$row['patient_id'],'dentist_user_id'=>(int)($row['dentist_user_id']??0),'dentist_name'=>(string)($row['dentist_name']??''),'assistant_user_id'=>(int)($row['assistant_user_id']??0),'assistant_name'=>(string)($row['assistant_name']??''),'chair_id'=>(int)($row['chair_id']??0),'chair_name'=>(string)($row['chair_name']??''),'label'=>(string)$row['patient_no'].' · '.(string)$row['last_name'].', '.(string)$row['first_name'],'meta'=>'Encounter #'.(int)$row['id'].' · '.(string)($row['dentist_name']?:'Dentist not assigned').($row['assistant_name']?' · Assistant '.(string)$row['assistant_name']:'').($row['chair_name']?' · '.(string)$row['chair_name']:'').' · '.ucwords(str_replace('_',' ',(string)$row['status']))];
            break;
        case 'inventory_issue':
            if($branchId<=0)throw new RuntimeException('Choose a branch before searching prior issues.');
            $stmt=$pdo->prepare('SELECT d.id,d.document_no,d.posted_at,p.patient_no,p.first_name,p.last_name,u.name requested_for FROM `' . table('inventory_documents') . '` d LEFT JOIN `' . table('patients') . '` p ON p.id=d.patient_id LEFT JOIN `' . table('users') . '` u ON u.id=d.requested_for_user_id WHERE d.branch_id=? AND d.document_type="issue" AND d.status="posted" AND (d.document_no LIKE ? OR p.patient_no LIKE ? OR p.first_name LIKE ? OR p.last_name LIKE ? OR u.name LIKE ?) ORDER BY d.posted_at DESC,d.id DESC LIMIT '.$limit);$stmt->execute([$branchId,$like,$like,$like,$like,$like]);
            foreach($stmt->fetchAll() as $row)$rows[]=['id'=>(int)$row['id'],'label'=>(string)$row['document_no'],'meta'=>trim(($row['patient_no']?(string)$row['patient_no'].' · '.(string)$row['last_name'].', '.(string)$row['first_name']:'').($row['requested_for']?' · '.(string)$row['requested_for']:'').($row['posted_at']?' · '.date('M j, Y',strtotime((string)$row['posted_at'])):''),' ·')];
            break;
        case 'instrument_set':
            $allowedStatuses=['dirty','prepared','sterile','in_use','quarantined'];$status=trim((string)($_GET['status']??''));if(!in_array($status,$allowedStatuses,true))$status='';
            $sql='SELECT id,set_code,name,status FROM `' . table('instrument_sets') . '` WHERE (set_code LIKE ? OR name LIKE ? OR contents LIKE ?)';$args=[$like,$like,$like];if($branchId>0){$sql.=' AND branch_id=?';$args[]=$branchId;}if($status!==''){$sql.=' AND status=?';$args[]=$status;}$sql.=' ORDER BY name LIMIT '.$limit;$stmt=$pdo->prepare($sql);$stmt->execute($args);
            foreach($stmt->fetchAll() as $row)$rows[]=['id'=>(int)$row['id'],'label'=>(string)$row['set_code'].' · '.(string)$row['name'],'meta'=>ucwords(str_replace('_',' ',(string)$row['status']))];
            break;
        case 'invoice':
            $patientId=max(0,(int)($_GET['patient_id']??0));if($patientId<=0)throw new RuntimeException('Choose a patient before searching invoices.');
            $sql='SELECT i.id,i.invoice_no,i.amount,i.paid_amount,i.status,i.created_at FROM `' . table('invoices') . '` i WHERE i.patient_id=? AND i.status NOT IN ("voided","refunded","written_off") AND (i.invoice_no LIKE ? OR i.status LIKE ?)';$args=[$patientId,$like,$like];if($branchId>0){$sql.=' AND i.branch_id=?';$args[]=$branchId;}$sql.=' ORDER BY i.created_at DESC LIMIT '.$limit;$stmt=$pdo->prepare($sql);$stmt->execute($args);
            foreach($stmt->fetchAll() as $row)$rows[]=['id'=>(int)$row['id'],'label'=>(string)$row['invoice_no'].' · ₱'.number_format((float)$row['amount'],2),'meta'=>ucwords(str_replace('_',' ',(string)$row['status'])).' · balance ₱'.number_format(max(0,(float)$row['amount']-(float)$row['paid_amount']),2)];
            break;
        case 'insurance_coverage':
            $patientId=max(0,(int)($_GET['patient_id']??0));if($patientId<=0)throw new RuntimeException('Choose a patient before searching coverage.');
            $sql='SELECT pi.id,pi.provider,pi.member_no,pi.plan_name,pi.coverage_start,pi.coverage_end FROM `' . table('patient_insurance') . '` pi JOIN `' . table('patients') . '` p ON p.id=pi.patient_id WHERE pi.patient_id=? AND pi.is_active=1 AND (pi.provider LIKE ? OR pi.member_no LIKE ? OR pi.plan_name LIKE ?)';$args=[$patientId,$like,$like,$like];if($branchId>0){$sql.=' AND (p.branch_id=? OR p.branch_id IS NULL)';$args[]=$branchId;}$sql.=' ORDER BY pi.created_at DESC LIMIT '.$limit;$stmt=$pdo->prepare($sql);$stmt->execute($args);
            foreach($stmt->fetchAll() as $row)$rows[]=['id'=>(int)$row['id'],'label'=>(string)$row['provider'].($row['member_no']?' · '.(string)$row['member_no']:''),'meta'=>trim((string)($row['plan_name']??'').($row['coverage_end']?' · through '.(string)$row['coverage_end']:''),' ·')];
            break;
        case 'sterilization_equipment':
            $sql='SELECT id,name,serial_number,next_service_date FROM `' . table('sterilization_equipment') . '` WHERE status="active" AND next_service_date IS NOT NULL AND next_service_date>=CURDATE() AND (name LIKE ? OR serial_number LIKE ? OR manufacturer LIKE ? OR model LIKE ?)';$args=[$like,$like,$like,$like];if($branchId>0){$sql.=' AND branch_id=?';$args[]=$branchId;}$sql.=' ORDER BY name LIMIT '.$limit;$stmt=$pdo->prepare($sql);$stmt->execute($args);
            foreach($stmt->fetchAll() as $row)$rows[]=['id'=>(int)$row['id'],'label'=>(string)$row['name'].' · '.(string)$row['serial_number'],'meta'=>'Service valid through '.(string)$row['next_service_date']];
            break;
        default: throw new RuntimeException('Unsupported lookup type.');
    }
    lookup_reply(200,['ok'=>true,'results'=>$rows,'message'=>$rows?'':'No matching record found.']);
}catch(Throwable $e){lookup_reply(422,['ok'=>false,'results'=>[],'message'=>$e->getMessage()]);}
