<?php

declare(strict_types=1);

require DENTAL_ROOT . '/app/bootstrap.php';
require_login();
require_documentation_schema();
require_permission('insurance.manage', ['super_admin','clinic_admin','cashier','receptionist']);
require DENTAL_ROOT . '/app/layout.php';
require_once DENTAL_ROOT . '/app/module_helpers.php';
require_once DENTAL_ROOT . '/app/revenue_integrity.php';

$pdo = db();
$userId = (int)(current_user()['id'] ?? 0);
$branchId = signed_user_branch_id();
if ($branchId < 1 && !superuser_primary_workspace()) {
    http_response_code(403);
    exit('Assign this insurance user to a clinic branch before opening Insurance & HMO.');
}
if ($branchId < 1 && superuser_primary_workspace()) {
    $branchId = (int)($pdo->query('SELECT id FROM `' . table('branches') . '` WHERE is_active=1 ORDER BY id LIMIT 1')->fetchColumn() ?: 0);
}
$canCoverage = revenue_is_supervisor();
$canClaims = task_context_action_allowed('insurance.financial') || $canCoverage;
$patientId = (int)($_GET['patient_id'] ?? 0);
$selectedPatient=null;
if($patientId>0){$patientStmt=$pdo->prepare('SELECT p.id,p.patient_no,p.first_name,p.last_name,p.mobile,p.email,p.primary_dentist_user_id,u.name primary_dentist_name FROM `' . table('patients') . '` p LEFT JOIN `' . table('users') . '` u ON u.id=p.primary_dentist_user_id WHERE p.id=? AND p.deleted_at IS NULL AND (p.branch_id=? OR p.branch_id IS NULL) LIMIT 1');$patientStmt->execute([$patientId,$branchId]);$selectedPatient=$patientStmt->fetch()?:null;if(!$selectedPatient)$patientId=0;}
$view = (string)($_GET['view'] ?? 'coverage');
$error = '';
$schemaReady = revenue_schema_ready();

function insurance_invoice(PDO $pdo, int $invoiceId, int $patientId, int $branchId, bool $forUpdate = false): array
{
    $stmt = $pdo->prepare(
        'SELECT * FROM `' . table('invoices') . '` WHERE id=? AND patient_id=? AND branch_id=? LIMIT 1'
        . ($forUpdate ? ' FOR UPDATE' : '')
    );
    $stmt->execute([$invoiceId,$patientId,$branchId]);
    $invoice = $stmt->fetch();
    if (!$invoice || in_array((string)$invoice['status'], ['voided','refunded','written_off'], true)) {
        throw new RuntimeException('The selected invoice is not available for this patient and branch.');
    }
    return $invoice;
}

function insurance_record_history(PDO $pdo, int $claimId, ?string $previousStatus, string $newStatus, float $claimed, float $approved, float $denied, ?string $submissionReference, ?string $remittanceReference, ?string $notes, int $userId): void
{
    $stmt = $pdo->prepare(
        'INSERT INTO `' . table('insurance_claim_history') . '` '
        . '(claim_id,previous_status,new_status,claimed_amount,approved_amount,denied_amount,submission_reference,remittance_reference,notes,changed_by,created_at) '
        . 'VALUES (?,?,?,?,?,?,?,?,?,?,NOW())'
    );
    $stmt->execute([$claimId,$previousStatus,$newStatus,$claimed,$approved,$denied,$submissionReference,$remittanceReference,$notes,$userId ?: null]);
}

$remittanceReferenceLock = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    try {
        verify_csrf();
        $action = (string)($_POST['action'] ?? '');
        if ($action === 'coverage' && !$canCoverage) throw new RuntimeException('Coverage setup requires the Administrator task view.');
        if (in_array($action, ['claim','claim_status','settle_claim'], true) && !$canClaims) throw new RuntimeException('This task view cannot process insurance claims.');

        if ($action === 'coverage') {
            $patientId = (int)($_POST['patient_id'] ?? 0);
            require_patient($patientId);
            $provider = trim((string)($_POST['provider'] ?? ''));
            if ($provider === '') throw new RuntimeException('Enter the insurance or HMO provider.');
            $pdo->prepare(
                'INSERT INTO `' . table('patient_insurance') . '` '
                . '(patient_id,provider,member_no,plan_name,policy_holder,relationship_to_holder,coverage_start,coverage_end,authorization_required,is_active,created_at) '
                . 'VALUES (?,?,?,?,?,?,?,?,?,1,NOW())'
            )->execute([
                $patientId,$provider,trim((string)($_POST['member_no'] ?? '')),trim((string)($_POST['plan_name'] ?? '')),
                trim((string)($_POST['policy_holder'] ?? '')),trim((string)($_POST['relationship_to_holder'] ?? '')),
                ($_POST['coverage_start'] ?? '') ?: null,($_POST['coverage_end'] ?? '') ?: null,isset($_POST['authorization_required']) ? 1 : 0,
            ]);
            audit('insurance_coverage_added','patient_insurance',(int)$pdo->lastInsertId(),['patient_id'=>$patientId]);
            module_return('insurance.php?patient_id=' . $patientId . '&view=coverage','success','Insurance or HMO coverage added.');
        }

        if ($action === 'claim') {
            if (!$schemaReady) throw new RuntimeException('Apply Version 0.5.9.7 before creating governed insurance claims.');
            $patientId = (int)($_POST['patient_id'] ?? 0);
            $invoiceId = (int)($_POST['invoice_id'] ?? 0);
            $insuranceId = (int)($_POST['insurance_id'] ?? 0);
            require_patient($patientId);
            $pdo->beginTransaction();
            $invoice = insurance_invoice($pdo,$invoiceId,$patientId,$branchId,true);
            revenue_assert_invoice_integrity($pdo, $invoice);
            $claimLock = $pdo->prepare('UPDATE `' . table('invoices') . '` SET charge_locked_at=COALESCE(charge_locked_at,NOW()),charge_locked_by=COALESCE(charge_locked_by,?),updated_at=NOW() WHERE id=? AND branch_id=?');
            $claimLock->execute([$userId,$invoiceId,$branchId]);
            if ($insuranceId < 1) throw new RuntimeException('Select the active insurance or HMO coverage used for this claim.');
            $stmt = $pdo->prepare('SELECT * FROM `' . table('patient_insurance') . '` WHERE id=? AND patient_id=? AND is_active=1 LIMIT 1');
            $stmt->execute([$insuranceId,$patientId]);
            $coverageRow = $stmt->fetch();
            if (!$coverageRow) throw new RuntimeException('The selected active coverage does not belong to this patient.');
            $today = date('Y-m-d');
            if (!empty($coverageRow['coverage_start']) && (string)$coverageRow['coverage_start'] > $today) throw new RuntimeException('This coverage is not yet effective.');
            if (!empty($coverageRow['coverage_end']) && (string)$coverageRow['coverage_end'] < $today) throw new RuntimeException('This coverage has expired.');
            $authorizationNo = trim((string)($_POST['authorization_no'] ?? ''));
            if (!empty($coverageRow['authorization_required']) && $authorizationNo === '') throw new RuntimeException('Enter the insurer pre-authorization number required by this coverage.');
            $status = (string)($_POST['status'] ?? 'draft');
            if (!in_array($status, ['draft','ready'], true)) throw new RuntimeException('A new claim must start as Draft or Ready.');
            $claimed = round((float)($_POST['claimed_amount'] ?? 0), 2);
            $invoiceBalance = max(0,round((float)$invoice['amount']-(float)$invoice['paid_amount'],2));
            $existingStmt = $pdo->prepare('SELECT COALESCE(SUM(claimed_amount),0) FROM `' . table('insurance_claims') . '` WHERE invoice_id=? AND status NOT IN ("denied","paid","closed")');
            $existingStmt->execute([$invoiceId]);
            $activeClaimExposure = round((float)$existingStmt->fetchColumn(),2);
            $claimable = max(0,round($invoiceBalance-$activeClaimExposure,2));
            if ($claimed <= 0 || $claimed > $claimable + 0.001) throw new RuntimeException('Claimed amount must be positive and cannot exceed the unallocated invoice balance of ₱' . number_format($claimable,2) . '.');
            $notes = trim((string)($_POST['notes'] ?? '')) ?: null;
            $pdo->prepare(
                'INSERT INTO `' . table('insurance_claims') . '` '
                . '(patient_id,insurance_id,invoice_id,claim_no,authorization_no,submission_reference,status,claimed_amount,approved_amount,denied_amount,reason,notes,created_by,updated_by,created_at) '
                . 'VALUES (?,?,?,?,?,NULL,?,?,0,0,?,?,?,?,NOW())'
            )->execute([
                $patientId,$insuranceId,$invoiceId,trim((string)($_POST['claim_no'] ?? '')) ?: null,$authorizationNo ?: null,$status,$claimed,
                trim((string)($_POST['reason'] ?? '')) ?: null,$notes,$userId ?: null,$userId ?: null,
            ]);
            $claimId = (int)$pdo->lastInsertId();
            insurance_record_history($pdo,$claimId,null,$status,$claimed,0,0,null,null,$notes,$userId);
            audit('insurance_claim_created','insurance_claim',$claimId,['patient_id'=>$patientId,'invoice_id'=>$invoiceId,'claimed_amount'=>$claimed,'authorization_no'=>$authorizationNo ?: null]);
            $pdo->commit();
            module_return('insurance.php?patient_id=' . $patientId . '&view=claims','success','Insurance claim saved.');
        }

        if ($action === 'claim_status') {
            $id = (int)($_POST['id'] ?? 0);
            $status = (string)($_POST['status'] ?? '');
            if ($status === 'paid') throw new RuntimeException('Paid status is created only by posting an insurer remittance to the invoice.');
            $pdo->beginTransaction();
            $stmt = $pdo->prepare(
                'SELECT c.*,i.branch_id,i.amount invoice_amount FROM `' . table('insurance_claims') . '` c '
                . 'JOIN `' . table('invoices') . '` i ON i.id=c.invoice_id WHERE c.id=? AND i.branch_id=? FOR UPDATE'
            );
            $stmt->execute([$id,$branchId]);
            $claim = $stmt->fetch();
            if (!$claim) throw new RuntimeException('Insurance claim not found for this branch.');
            if (!revenue_claim_transition_allowed((string)$claim['status'],$status)) throw new RuntimeException('The claim cannot move from ' . module_status((string)$claim['status']) . ' to ' . module_status($status) . '.');
            $approved = round((float)($_POST['approved_amount'] ?? 0), 2);
            $denied = round((float)($_POST['denied_amount'] ?? 0), 2);
            $claimed = round((float)$claim['claimed_amount'],2);
            if ($approved < 0 || $denied < 0 || $approved + $denied > $claimed + 0.001) throw new RuntimeException('Approved plus denied amount cannot exceed the claimed amount.');
            if ($status === 'approved' && (abs($approved-$claimed)>0.001 || $denied>0.001)) throw new RuntimeException('Approved claims must adjudicate the full claimed amount with no denied balance.');
            if ($status === 'partially_approved' && ($approved <= 0 || $denied <= 0 || abs(($approved+$denied)-$claimed)>0.001)) throw new RuntimeException('A partial approval must allocate the entire claim between approved and denied amounts.');
            if ($status === 'denied' && (abs($denied-$claimed)>0.001 || $approved>0.001)) throw new RuntimeException('Denied claims must assign the full claimed amount as denied.');
            if ($status === 'closed' && in_array((string)$claim['status'],['approved','partially_approved'],true) && empty($claim['payment_id'])) throw new RuntimeException('An approved claim cannot be closed before its insurer remittance is allocated.');
            $submissionReference = trim((string)($_POST['submission_reference'] ?? ($claim['submission_reference'] ?? '')));
            if (in_array($status,['submitted','pending','information_required','approved','partially_approved','denied'],true) && $submissionReference === '') throw new RuntimeException('Enter the insurer submission or response reference before moving this claim beyond Ready.');
            $notes = trim((string)($_POST['notes'] ?? '')) ?: null;
            $submittedAt = in_array($status,['submitted','pending','information_required','approved','partially_approved','denied'],true) ? 'COALESCE(submitted_at,NOW())' : 'submitted_at';
            $sql = 'UPDATE `' . table('insurance_claims') . '` SET status=?,approved_amount=?,denied_amount=?,submission_reference=?,submitted_at=' . $submittedAt . ',reason=?,notes=?,updated_by=?,updated_at=NOW() WHERE id=? AND status=?';
            $update=$pdo->prepare($sql);$update->execute([$status,$approved,$denied,$submissionReference ?: null,trim((string)($_POST['reason'] ?? '')) ?: null,$notes,$userId ?: null,$id,(string)$claim['status']]);
            if($update->rowCount()!==1)throw new RuntimeException('The claim changed before this transition could be saved. Reload and review the latest state.');
            insurance_record_history($pdo,$id,(string)$claim['status'],$status,$claimed,$approved,$denied,$submissionReference ?: null,null,$notes,$userId);
            audit('insurance_claim_updated','insurance_claim',$id,['from'=>$claim['status'],'to'=>$status,'approved_amount'=>$approved,'denied_amount'=>$denied,'submission_reference'=>$submissionReference]);
            $pdo->commit();
            module_return('insurance.php?patient_id=' . (int)$claim['patient_id'] . '&view=claims','success','Claim status updated.');
        }

        if ($action === 'settle_claim') {
            if (!$schemaReady) throw new RuntimeException('Apply Version 0.5.9.7 before allocating insurer payments.');
            $id = (int)($_POST['id'] ?? 0);
            $amount = round((float)($_POST['settled_amount'] ?? 0), 2);
            $reference = trim((string)($_POST['remittance_reference'] ?? ''));
            if ($amount <= 0 || $reference === '') throw new RuntimeException('Enter the insurer amount received and remittance reference.');
            $pdo->beginTransaction();
            $stmt = $pdo->prepare(
                'SELECT c.*,i.branch_id,i.amount invoice_amount,i.paid_amount invoice_paid,i.status invoice_status,i.charge_source_hash '
                . 'FROM `' . table('insurance_claims') . '` c JOIN `' . table('invoices') . '` i ON i.id=c.invoice_id '
                . 'WHERE c.id=? AND i.branch_id=? FOR UPDATE'
            );
            $stmt->execute([$id,$branchId]);
            $claim = $stmt->fetch();
            if (!$claim) throw new RuntimeException('Insurance claim not found for this branch.');
            if (!in_array((string)$claim['status'], ['approved','partially_approved'], true)) throw new RuntimeException('Only an approved claim can receive an insurer remittance.');
            if (!empty($claim['payment_id']) || !empty($claim['settled_at'])) throw new RuntimeException('This claim already has a posted insurer remittance.');
            revenue_assert_invoice_integrity($pdo, ['id'=>(int)$claim['invoice_id'],'charge_source_hash'=>$claim['charge_source_hash'] ?? null]);
            $approved = round((float)$claim['approved_amount'], 2);
            $balance = max(0, round((float)$claim['invoice_amount'] - (float)$claim['invoice_paid'], 2));
            if (abs($amount-$approved) > 0.001) throw new RuntimeException('The remittance must equal the final approved amount of ₱' . number_format($approved,2) . '. Record a corrected adjudication or appeal before settlement.');
            if ($amount > $balance + 0.001) throw new RuntimeException('The approved insurer amount exceeds the current invoice balance of ₱' . number_format($balance,2) . '. Reconcile prior patient payments before settlement.');
            $remittanceReferenceLock = revenue_lock_name('insurance_remittance', $branchId, mb_strtolower($reference));
            revenue_acquire_lock($pdo, $remittanceReferenceLock);
            $duplicateStmt=$pdo->prepare('SELECT COUNT(*) FROM `' . table('payments') . '` p JOIN `' . table('invoices') . '` i ON i.id=p.invoice_id WHERE p.source_type="insurance" AND p.reference_no=? AND i.branch_id=?');
            $duplicateStmt->execute([$reference,$branchId]);
            if((int)$duplicateStmt->fetchColumn()>0)throw new RuntimeException('This insurer remittance reference has already been posted in this branch.');
            $pdo->prepare(
                'INSERT INTO `' . table('payments') . '` (invoice_id,cashier_session_id,source_type,status,amount,adjustment_total,tendered_amount,change_amount,method,reference_no,notes,received_by,created_at) '
                . 'VALUES (?,NULL,"insurance","posted",?,0,?,0,"insurance",?,?,?,NOW())'
            )->execute([(int)$claim['invoice_id'],$amount,$amount,$reference,trim((string)($_POST['notes'] ?? '')) ?: null,$userId ?: null]);
            $paymentId = (int)$pdo->lastInsertId();
            $newPaid = round((float)$claim['invoice_paid'] + $amount, 2);
            $invoiceStatus = $newPaid + 0.001 >= (float)$claim['invoice_amount'] ? 'paid' : 'partial';
            $invoicePaymentUpdate = $pdo->prepare('UPDATE `' . table('invoices') . '` SET paid_amount=?,status=?,charge_locked_at=COALESCE(charge_locked_at,NOW()),charge_locked_by=COALESCE(charge_locked_by,?),updated_at=NOW() WHERE id=? AND paid_amount=?');
            $invoicePaymentUpdate->execute([$newPaid,$invoiceStatus,$userId,(int)$claim['invoice_id'],(float)$claim['invoice_paid']]);
            if ($invoicePaymentUpdate->rowCount() !== 1) throw new RuntimeException('The invoice balance changed before the insurer remittance was allocated. Reload the claim and reconcile again.');
            $settlementNotes=trim((string)($_POST['notes'] ?? '')) ?: ($claim['notes'] ?? null);
            $claimUpdate=$pdo->prepare(
                'UPDATE `' . table('insurance_claims') . '` SET status="paid",paid_at=NOW(),remittance_reference=?,payment_id=?,settled_amount=?,settled_by=?,settled_at=NOW(),notes=?,updated_by=?,updated_at=NOW() WHERE id=? AND status=?'
            );
            $claimUpdate->execute([$reference,$paymentId,$amount,$userId,$settlementNotes,$userId ?: null,$id,(string)$claim['status']]);
            if($claimUpdate->rowCount()!==1)throw new RuntimeException('The claim changed before the remittance could be finalized.');
            insurance_record_history($pdo,$id,(string)$claim['status'],'paid',(float)$claim['claimed_amount'],(float)$claim['approved_amount'],(float)$claim['denied_amount'],(string)($claim['submission_reference']??'') ?: null,$reference,$settlementNotes,$userId);
            audit('insurance_claim_settled','insurance_claim',$id,['payment_id'=>$paymentId,'invoice_id'=>$claim['invoice_id'],'amount'=>$amount,'reference'=>$reference,'invoice_status'=>$invoiceStatus]);
            workflow_event((int)$claim['patient_id'],'insurance_payment_allocated','Insurance remittance allocated',['invoice_id'=>(int)$claim['invoice_id'],'payment_id'=>$paymentId],'₱' . number_format($amount,2) . ' · ' . $reference);
            $pdo->commit();
            if ($remittanceReferenceLock !== null) {
                revenue_release_lock($pdo, $remittanceReferenceLock);
                $remittanceReferenceLock = null;
            }
            module_return('insurance.php?patient_id=' . (int)$claim['patient_id'] . '&view=claims','success','Insurer remittance posted to the linked invoice.');
        }

        throw new RuntimeException('Unsupported insurance action.');
    } catch (Throwable $exception) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        if ($remittanceReferenceLock !== null) {
            revenue_release_lock($pdo, $remittanceReferenceLock);
            $remittanceReferenceLock = null;
        }
        $error = $exception->getMessage();
    }
}

$state = module_management_state('page', 'per_page', 25);
$page = $state['page'];
$perPage = $state['per_page'];
$offset = $state['offset'];
$q = trim((string)($_GET['q'] ?? ''));
$statusFilter = module_safe_status_filter('status', ['','draft','ready','submitted','pending','information_required','approved','partially_approved','denied','appealed','paid','closed','active','inactive']);
$manageId = max(0, (int)($_GET['manage_id'] ?? 0));

$whereParts = ['p.branch_id=?'];
$listParams = [$branchId];
if ($patientId > 0) { $whereParts[] = 'i.patient_id=?'; $listParams[] = $patientId; }
if ($q !== '') {
    $whereParts[] = '(i.provider LIKE ? OR i.member_no LIKE ? OR i.plan_name LIKE ? OR CONCAT(p.first_name," ",p.last_name) LIKE ?)';
    $like = module_like_term($q);
    array_push($listParams, $like, $like, $like, $like);
}
if ($statusFilter === 'active') $whereParts[] = 'i.is_active=1';
if ($statusFilter === 'inactive') $whereParts[] = 'i.is_active=0';
$coverageWhere = implode(' AND ', $whereParts);
$coverageTotalStmt = $pdo->prepare('SELECT COUNT(*) FROM `' . table('patient_insurance') . '` i JOIN `' . table('patients') . '` p ON p.id=i.patient_id WHERE ' . $coverageWhere);
$coverageTotalStmt->execute($listParams);
$coverageTotal = (int)$coverageTotalStmt->fetchColumn();
$coverageStmt = $pdo->prepare('SELECT i.*,CONCAT(p.first_name," ",p.last_name) patient FROM `' . table('patient_insurance') . '` i JOIN `' . table('patients') . '` p ON p.id=i.patient_id WHERE ' . $coverageWhere . ' ORDER BY i.is_active DESC,i.created_at DESC LIMIT ' . $perPage . ' OFFSET ' . $offset);
$coverageStmt->execute($listParams);
$coverage = $coverageStmt->fetchAll();

$claimWhereParts = ['inv.branch_id=?'];
$claimParams = [$branchId];
if ($patientId > 0) { $claimWhereParts[] = 'c.patient_id=?'; $claimParams[] = $patientId; }
if ($q !== '') {
    $claimWhereParts[] = '(c.claim_no LIKE ? OR c.authorization_no LIKE ? OR c.submission_reference LIKE ? OR inv.invoice_no LIKE ? OR pi.provider LIKE ? OR CONCAT(p.first_name," ",p.last_name) LIKE ?)';
    $like = module_like_term($q);
    array_push($claimParams, $like, $like, $like, $like, $like, $like);
}
if ($statusFilter !== '' && !in_array($statusFilter, ['active','inactive'], true)) { $claimWhereParts[] = 'c.status=?'; $claimParams[] = $statusFilter; }
$claimWhere = implode(' AND ', $claimWhereParts);
$claimFrom = ' FROM `' . table('insurance_claims') . '` c JOIN `' . table('patients') . '` p ON p.id=c.patient_id LEFT JOIN `' . table('patient_insurance') . '` pi ON pi.id=c.insurance_id JOIN `' . table('invoices') . '` inv ON inv.id=c.invoice_id ';
$claimTotalStmt = $pdo->prepare('SELECT COUNT(*)' . $claimFrom . 'WHERE ' . $claimWhere);
$claimTotalStmt->execute($claimParams);
$claimsTotal = (int)$claimTotalStmt->fetchColumn();
$claimStmt = $pdo->prepare('SELECT c.*,CONCAT(p.first_name," ",p.last_name) patient,pi.provider,inv.invoice_no,inv.amount invoice_amount,inv.paid_amount invoice_paid' . $claimFrom . 'WHERE ' . $claimWhere . ' ORDER BY c.created_at DESC LIMIT ' . $perPage . ' OFFSET ' . $offset);
$claimStmt->execute($claimParams);
$claims = $claimStmt->fetchAll();

$managedClaim = null;
$managedHistory = [];
if ($view === 'claims' && $manageId > 0) {
    $managedStmt = $pdo->prepare('SELECT c.*,CONCAT(p.first_name," ",p.last_name) patient,pi.provider,inv.invoice_no,inv.amount invoice_amount,inv.paid_amount invoice_paid' . $claimFrom . 'WHERE inv.branch_id=? AND c.id=? LIMIT 1');
    $managedStmt->execute([$branchId,$manageId]);
    $managedClaim = $managedStmt->fetch() ?: null;
    if ($managedClaim && $schemaReady) {
        $historyStmt = $pdo->prepare('SELECT h.*,u.name changed_by_name FROM `' . table('insurance_claim_history') . '` h LEFT JOIN `' . table('users') . '` u ON u.id=h.changed_by WHERE h.claim_id=? ORDER BY h.created_at DESC,h.id DESC LIMIT 25');
        $historyStmt->execute([$manageId]);
        $managedHistory = $historyStmt->fetchAll();
    }
}

$rowsTotal = $view === 'claims' ? $claimsTotal : $coverageTotal;

render_header('Insurance & HMO');
if ($error !== '') echo '<div class="alert danger"><strong>Insurance transaction was not completed.</strong><br>' . e($error) . '</div>';
if (!$schemaReady) echo '<div class="alert warning"><strong>Version 0.5.9.7 database update required.</strong> Claim settlement cannot be marked paid until the remittance is posted to the invoice.</div>';
?>
<div class="toolbar"><div class="tabs"><a class="<?=$view==='coverage'?'active':''?>" href="insurance.php?view=coverage<?=$patientId?'&patient_id='.$patientId:''?>">Coverage</a><a class="<?=$view==='claims'?'active':''?>" href="insurance.php?view=claims<?=$patientId?'&patient_id='.$patientId:''?>">Claims</a></div><div><?php if($canCoverage):?><button class="btn ghost" data-open="coverage-form">Add coverage</button><?php endif;?><?php if($canClaims):?><button class="btn primary" data-open="claim-form" <?=$patientId>0?'':'disabled'?>>New claim</button><?php endif;?></div></div>
<form method="get" class="card management-filters"><input type="hidden" name="view" value="<?=e($view)?>"><label class="wide">Patient filter<?php module_remote_patient_picker('patient_id',$selectedPatient,false,'Search patient number, name, mobile, or email');?></label><div class="filter-actions"><button class="btn primary">Open patient</button><?php if($patientId):?><a class="btn ghost" href="insurance.php?view=<?=e($view)?>">Show all</a><?php endif;?></div></form>
<form method="get" class="management-filter-bar"><input type="hidden" name="view" value="<?=e($view)?>"><?php if($patientId):?><input type="hidden" name="patient_id" value="<?=$patientId?>"><?php endif;?><label>Search<input name="q" value="<?=e($q)?>" placeholder="Patient, provider, invoice, member or claim no."></label><label>Status<select name="status"><option value="">All statuses</option><?php $filterStatuses=$view==='claims'?['draft','ready','submitted','pending','information_required','approved','partially_approved','denied','appealed','paid','closed']:['active','inactive'];foreach($filterStatuses as $filterStatus):?><option value="<?=e($filterStatus)?>" <?=$statusFilter===$filterStatus?'selected':''?>><?=e(module_status($filterStatus))?></option><?php endforeach;?></select></label><label>Rows<select name="per_page"><?php foreach([10,25,50,100] as $size):?><option value="<?=$size?>" <?=$perPage===$size?'selected':''?>><?=$size?></option><?php endforeach;?></select></label><button class="btn primary">Apply</button><a class="btn ghost" href="insurance.php?view=<?=e($view)?><?=$patientId?'&patient_id='.$patientId:''?>">Reset</a></form>
<div class="card server-list-card"><?php module_render_list_count($rowsTotal,$view==='claims'?'claims':'coverage records');module_render_server_pagination($rowsTotal,$page,$perPage,'page','per_page','insurance-list');?><div class="table-wrap"><table><thead><tr><?php if($view==='claims'):?><th>Patient / provider</th><th>Invoice / references</th><th>Claimed</th><th>Adjudication</th><th>Status</th><th>Action</th><?php else:?><th>Patient / provider</th><th>Member / plan</th><th>Coverage</th><th>Authorization</th><th>Status</th><?php endif;?></tr></thead><tbody>
<?php if($view==='claims'):foreach($claims as $row):$balance=max(0,(float)$row['invoice_amount']-(float)$row['invoice_paid']);?><tr><td><strong><?=e((string)$row['patient'])?></strong><small><?=e((string)($row['provider']?:'Insurance/HMO'))?></small></td><td><strong><?=e((string)$row['invoice_no'])?></strong><small><?=e((string)($row['claim_no']?:'No claim number'))?> · <?=e((string)($row['submission_reference']?:'No submission reference'))?></small></td><td>₱<?=number_format((float)$row['claimed_amount'],2)?><small>Invoice balance ₱<?=number_format($balance,2)?></small></td><td>Approved ₱<?=number_format((float)$row['approved_amount'],2)?><small>Denied ₱<?=number_format((float)$row['denied_amount'],2)?></small></td><td><span class="badge"><?=e(module_status((string)$row['status']))?></span></td><td><a class="btn ghost" href="<?=e(module_management_url(['manage_id'=>(int)$row['id'],'page'=>$page,'per_page'=>$perPage]))?>">Manage</a></td></tr><?php endforeach;if(!$claims):?><tr><td colspan="6" class="muted">No claims match the current filters.</td></tr><?php endif;else:foreach($coverage as $row):?><tr><td><strong><?=e((string)$row['patient'])?></strong><small><?=e((string)$row['provider'])?></small></td><td><?=e((string)($row['member_no']?:'—'))?><small><?=e((string)($row['plan_name']?:'No plan name'))?></small></td><td><?=e((string)($row['coverage_start']?:'Open'))?> to <?=e((string)($row['coverage_end']?:'Open'))?></td><td><?=$row['authorization_required']?'Required':'Not required'?></td><td><span class="badge"><?=$row['is_active']?'Active':'Inactive'?></span></td></tr><?php endforeach;if(!$coverage):?><tr><td colspan="5" class="muted">No coverage records match the current filters.</td></tr><?php endif;endif;?></tbody></table></div><?php module_render_server_pagination($rowsTotal,$page,$perPage,'page','per_page','insurance-list');?></div>

<?php if($managedClaim):$managedBalance=max(0,(float)$managedClaim['invoice_amount']-(float)$managedClaim['invoice_paid']);?><dialog id="claim-manage" class="wide-dialog" data-auto-open-dialog="claim-manage"><form method="dialog"><button type="submit" class="dialog-close">×</button></form><div class="dialog-scroll"><h2>Manage insurance claim</h2><div class="detail-grid"><div><small>Patient</small><strong><?=e((string)$managedClaim['patient'])?></strong></div><div><small>Provider</small><strong><?=e((string)($managedClaim['provider']?:'Insurance/HMO'))?></strong></div><div><small>Invoice</small><strong><?=e((string)$managedClaim['invoice_no'])?></strong></div><div><small>Balance</small><strong>₱<?=number_format($managedBalance,2)?></strong></div></div>
<?php if($canClaims&&!in_array($managedClaim['status'],['paid','closed'],true)):?><form method="post" class="form-grid"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="claim_status"><input type="hidden" name="id" value="<?=(int)$managedClaim['id']?>"><label>Status<select name="status"><?php foreach(['draft','ready','submitted','pending','information_required','approved','partially_approved','denied','appealed','closed'] as $claimStatus):?><option value="<?=e($claimStatus)?>" <?=$managedClaim['status']===$claimStatus?'selected':''?>><?=e(module_status($claimStatus))?></option><?php endforeach;?></select></label><label>Submission / response reference<input name="submission_reference" value="<?=e((string)($managedClaim['submission_reference']??''))?>"></label><label>Approved<input type="number" min="0" step="0.01" name="approved_amount" value="<?=e((string)$managedClaim['approved_amount'])?>"></label><label>Denied<input type="number" min="0" step="0.01" name="denied_amount" value="<?=e((string)$managedClaim['denied_amount'])?>"></label><label class="wide">Reason<input name="reason" value="<?=e((string)$managedClaim['reason'])?>"></label><label class="wide">Notes<textarea name="notes"><?=e((string)$managedClaim['notes'])?></textarea></label><button class="btn primary">Update claim</button></form><?php endif;?>
<?php if($canClaims&&in_array($managedClaim['status'],['approved','partially_approved'],true)&&!$managedClaim['payment_id']):?><hr><form method="post" class="form-grid"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="settle_claim"><input type="hidden" name="id" value="<?=(int)$managedClaim['id']?>"><h3 class="wide">Post insurer remittance</h3><label>Approved amount due<input type="number" min="0.01" step="0.01" name="settled_amount" value="<?=e(number_format((float)$managedClaim['approved_amount'],2,'.',''))?>" readonly required></label><label>Remittance reference<input name="remittance_reference" required></label><label class="wide">Settlement notes<textarea name="notes"></textarea></label><button class="btn primary" <?=$schemaReady&&$managedBalance>=(float)$managedClaim['approved_amount']?'':'disabled'?>>Allocate payment to invoice</button></form><?php endif;?>
<?php if($managedHistory):?><hr><h3>Recent transaction history</h3><p class="muted">Showing the latest 25 claim events.</p><div class="timeline-list"><?php foreach($managedHistory as $history):?><article class="timeline-item"><h4><?=e(module_status((string)$history['new_status']))?></h4><p><?=e(module_status((string)($history['previous_status']?:'created')))?> → <?=e(module_status((string)$history['new_status']))?> · Claimed ₱<?=number_format((float)$history['claimed_amount'],2)?> · Approved ₱<?=number_format((float)$history['approved_amount'],2)?> · Denied ₱<?=number_format((float)$history['denied_amount'],2)?></p><small><?=e(date('M j, Y g:i A',strtotime((string)$history['created_at'])))?> · <?=e((string)($history['changed_by_name']?:'System'))?></small></article><?php endforeach;?></div><?php endif;?></div></dialog><?php endif;?>

<?php if($canCoverage):?><dialog id="coverage-form" class="wide-dialog"><form method="post" class="form-grid"><button type="button" class="dialog-close" data-close>×</button><h2 class="wide">Add insurance or HMO coverage</h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="coverage"><label class="wide">Patient<?php module_remote_patient_picker('patient_id',$selectedPatient,true,'Search and select patient');?></label><label>Provider<input name="provider" required></label><label>Member number<input name="member_no"></label><label>Plan<input name="plan_name"></label><label>Policy holder<input name="policy_holder"></label><label>Relationship<input name="relationship_to_holder"></label><label>Coverage start<input type="date" name="coverage_start"></label><label>Coverage end<input type="date" name="coverage_end"></label><label class="check-option wide"><input type="checkbox" name="authorization_required"><span>Pre-authorization is required</span></label><button class="btn primary">Save coverage</button></form></dialog><?php endif;?>
<?php if($canClaims):?><dialog id="claim-form" class="wide-dialog"><form method="post" class="form-grid"><button type="button" class="dialog-close" data-close>×</button><h2 class="wide">Create insurance claim</h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="claim"><input type="hidden" name="patient_id" value="<?=$patientId?>"><?php if($patientId&&$selectedPatient):?><div class="notice info wide"><strong><?=e((string)$selectedPatient['last_name'].', '.(string)$selectedPatient['first_name'])?></strong> · <?=e((string)$selectedPatient['patient_no'])?></div><label>Coverage<?php module_remote_record_picker('insurance_id','insurance_coverage',$branchId,true,'Search provider, member number, or plan',null,['patient_id'=>$patientId]);?></label><label>Pre-authorization number<input name="authorization_no"></label><label>Invoice<?php module_remote_record_picker('invoice_id','invoice',$branchId,true,'Search invoice number or status',null,['patient_id'=>$patientId]);?></label><label>Claim number<input name="claim_no"></label><label>Claimed amount<input type="number" min="0.01" step="0.01" name="claimed_amount" required></label><label>Status<select name="status"><option value="draft">Draft</option><option value="ready">Ready for submission</option></select></label><label class="wide">Reason<textarea name="reason"></textarea></label><label class="wide">Notes<textarea name="notes"></textarea></label><button class="btn primary">Save claim</button><?php else:?><div class="alert warning wide">Select a patient from the page filter before creating a claim.</div><?php endif;?></form></dialog><?php endif;?>
<?php render_footer(); ?>
