<?php

declare(strict_types=1);

require DENTAL_ROOT . '/app/bootstrap.php';
require_login();
if (!signed_identity_has_role(['super_admin','clinic_admin'])) {
    access_denied('Only an Administrator or Superuser can access privacy governance.');
}
require DENTAL_ROOT . '/app/layout.php';

$pdo = db();
$schemaReady = dental_privacy_schema_ready();
$canGovernance = can('privacy.governance.manage', ['super_admin','clinic_admin']);
$canRequests = can('privacy.requests.manage', ['super_admin','clinic_admin']);
$canIncidents = can('privacy.incidents.manage', ['super_admin','clinic_admin']);
$canVerifyAudit = can('audit.integrity.verify', ['super_admin','clinic_admin']);
$canExportAudit = can('audit.export', ['super_admin','clinic_admin']);
if (!$canGovernance && !$canRequests && !$canIncidents && !$canVerifyAudit && !$canExportAudit) {
    access_denied('Your active Task View does not have privacy-governance authority.');
}

$scopeBranch = dental_privacy_branch_scope();
$branchFilter = static function (string $alias = '') use ($scopeBranch): array {
    if ($scopeBranch === null) return ['', []];
    $column = ($alias !== '' ? $alias . '.' : '') . 'branch_id';
    return [' WHERE ' . $column . '=?', [$scopeBranch]];
};

if ($schemaReady && ($_GET['export'] ?? '') === 'audit_manifest') {
    require_permission('audit.export', ['super_admin','clinic_admin']);
    audit_required('audit_integrity_manifest_exported', 'audit_log', null, ['branch_scope'=>$scopeBranch]);
    $audit = table('audit_logs');
    $where = $scopeBranch === null ? '' : ' WHERE branch_id=' . (int)$scopeBranch;
    $rows = $pdo->query(
        'SELECT id,user_id,branch_id,action,entity_type,entity_id,created_at,record_hash,chain_key,chain_sequence,previous_hash,integrity_version '
        . 'FROM `' . $audit . '`' . $where . ' ORDER BY id DESC LIMIT 5000'
    )->fetchAll();
    header('Content-Type: text/csv; charset=utf-8');
    header('Content-Disposition: attachment; filename="DentalCare_Audit_Integrity_Manifest_' . date('Ymd_His') . '.csv"');
    $out = fopen('php://output', 'wb');
    fputcsv($out, ['id','user_id','branch_id','action','entity_type','entity_id','created_at','record_hash','chain_key','chain_sequence','previous_hash','integrity_version']);
    foreach ($rows as $row) fputcsv($out, $row);
    fclose($out);
    exit;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    try {
        verify_csrf();
        if (!$schemaReady) throw new RuntimeException('Apply database update 0.9.0.6 before using privacy governance.');
        $action = trim((string)($_POST['action'] ?? ''));
        $requestedBranch = (int)($_POST['branch_id'] ?? 0);
        $branchId = $scopeBranch === null ? ($requestedBranch > 0 ? $requestedBranch : null) : $scopeBranch;
        if ($branchId !== null && $branchId < 1) $branchId = null;
        if (!dental_privacy_branch_allowed($branchId) && !superuser_primary_workspace()) {
            throw new RuntimeException('The selected branch is outside your administrative scope.');
        }

        if ($action === 'verify_audit') {
            require_permission('audit.integrity.verify', ['super_admin','clinic_admin']);
            $result = dental_audit_integrity_snapshot_create(5000);
            flash($result['status'] === 'verified' ? 'success' : 'error',
                $result['status'] === 'verified'
                    ? 'Audit-chain verification completed without detected breaks.'
                    : 'Audit-chain verification detected a problem. Review the snapshot before production use.');
        } elseif ($action === 'create_processing') {
            require_permission('privacy.governance.manage', ['super_admin','clinic_admin']);
            $title = trim((string)($_POST['title'] ?? ''));
            $purpose = trim((string)($_POST['purpose'] ?? ''));
            $legalBasis = trim((string)($_POST['legal_basis'] ?? ''));
            if (mb_strlen($title) < 3 || mb_strlen($purpose) < 10 || mb_strlen($legalBasis) < 3) {
                throw new RuntimeException('Processing title, purpose, and legal basis are required.');
            }
            $stmt = $pdo->prepare('INSERT INTO `' . dental_privacy_processing_table() . '` '
                . '(branch_id,title,purpose,data_categories,data_subjects,legal_basis,recipients,international_transfer,safeguards,status,owner_user_id,review_due_at,created_by,created_at,updated_at) '
                . 'VALUES (?,?,?,?,?,?,?,?,?,"active",?,?,?,NOW(),NOW())');
            $stmt->execute([$branchId,$title,$purpose,trim((string)($_POST['data_categories']??'')),trim((string)($_POST['data_subjects']??'')),$legalBasis,trim((string)($_POST['recipients']??'')),trim((string)($_POST['international_transfer']??'')),trim((string)($_POST['safeguards']??'')),current_user()['id']??null,dental_privacy_clean_date($_POST['review_due_at']??null),current_user()['id']??null]);
            $id=(int)$pdo->lastInsertId();
            audit_required('privacy_processing_activity_created','privacy_processing_activity',$id,['branch_id'=>$branchId,'title'=>$title,'legal_basis'=>$legalBasis]);
            flash('success','Processing activity recorded.');
        } elseif ($action === 'create_retention') {
            require_permission('privacy.governance.manage', ['super_admin','clinic_admin']);
            $category=trim((string)($_POST['record_category']??''));
            $months=max(1,min(1200,(int)($_POST['retention_months']??0)));
            if (mb_strlen($category)<3 || $months<1) throw new RuntimeException('Record category and retention period are required.');
            $stmt=$pdo->prepare('INSERT INTO `' . dental_privacy_retention_table() . '` (branch_id,record_category,retention_months,trigger_event,legal_basis,disposition_action,legal_hold_allowed,is_active,review_due_at,created_by,created_at,updated_at) VALUES (?,?,?,?,?,?,?,1,?,?,NOW(),NOW())');
            $stmt->execute([$branchId,$category,$months,trim((string)($_POST['trigger_event']??'Record closure')),
                trim((string)($_POST['legal_basis']??'')),trim((string)($_POST['disposition_action']??'Secure deletion or anonymization')),
                isset($_POST['legal_hold_allowed'])?1:0,dental_privacy_clean_date($_POST['review_due_at']??null),current_user()['id']??null]);
            $id=(int)$pdo->lastInsertId();
            audit_required('privacy_retention_rule_created','privacy_retention_rule',$id,['branch_id'=>$branchId,'record_category'=>$category,'retention_months'=>$months]);
            flash('success','Retention rule recorded.');
        } elseif ($action === 'create_request') {
            require_permission('privacy.requests.manage', ['super_admin','clinic_admin']);
            $name=trim((string)($_POST['requester_name']??''));
            $type=trim((string)($_POST['request_type']??''));
            if (mb_strlen($name)<2 || $type==='') throw new RuntimeException('Requester and request type are required.');
            $reference=dental_privacy_reference('DSR');
            $received=dental_privacy_clean_date($_POST['received_at']??null) ?: date('Y-m-d');
            $due=dental_privacy_clean_date($_POST['due_at']??null) ?: date('Y-m-d',strtotime($received.' +30 days'));
            $stmt=$pdo->prepare('INSERT INTO `' . dental_privacy_requests_table() . '` (branch_id,request_reference,patient_id,requester_name,requester_contact,request_type,received_at,due_at,status,identity_verification_status,assigned_user_id,notes,created_by,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,"received","pending",?,?,?,NOW(),NOW())');
            $patientId=(int)($_POST['patient_id']??0);
            $stmt->execute([$branchId,$reference,$patientId>0?$patientId:null,$name,trim((string)($_POST['requester_contact']??'')),$type,$received,$due,current_user()['id']??null,trim((string)($_POST['notes']??'')),current_user()['id']??null]);
            $id=(int)$pdo->lastInsertId();
            audit_required('privacy_rights_request_created','privacy_rights_request',$id,['branch_id'=>$branchId,'reference'=>$reference,'request_type'=>$type,'due_at'=>$due]);
            flash('success','Privacy-rights request '.$reference.' recorded.');
        } elseif ($action === 'update_request') {
            require_permission('privacy.requests.manage', ['super_admin','clinic_admin']);
            $id=(int)($_POST['id']??0);$status=trim((string)($_POST['status']??''));
            $allowed=['received','identity_check','in_progress','waiting_for_requester','completed','rejected','withdrawn'];
            if($id<1||!in_array($status,$allowed,true))throw new RuntimeException('The rights-request update is invalid.');
            [$where,$args]=$branchFilter();
            $read=$pdo->prepare('SELECT * FROM `' . dental_privacy_requests_table() . '` WHERE id=?'.($where!==''?' AND branch_id=?':''));
            $read->execute(array_merge([$id],$args));$old=$read->fetch();if(!$old)throw new RuntimeException('The rights request was not found in your branch scope.');
            $identity=trim((string)($_POST['identity_verification_status']??'pending'));
            if(!in_array($identity,['pending','verified','failed','not_required'],true))$identity='pending';
            $completed=in_array($status,['completed','rejected','withdrawn'],true)?date('Y-m-d H:i:s'):null;
            $stmt=$pdo->prepare('UPDATE `' . dental_privacy_requests_table() . '` SET status=?,identity_verification_status=?,identity_verified_at=?,outcome_summary=?,completed_at=?,updated_at=NOW() WHERE id=?');
            $stmt->execute([$status,$identity,$identity==='verified'?date('Y-m-d H:i:s'):null,trim((string)($_POST['outcome_summary']??'')),$completed,$id]);
            audit_required('privacy_rights_request_updated','privacy_rights_request',$id,['status'=>$status,'identity_verification_status'=>$identity],['status'=>$old['status'],'identity_verification_status'=>$old['identity_verification_status']]);
            flash('success','Privacy-rights request updated.');
        } elseif ($action === 'create_incident') {
            require_permission('privacy.incidents.manage', ['super_admin','clinic_admin']);
            $title=trim((string)($_POST['title']??''));$severity=trim((string)($_POST['severity']??'medium'));
            if(mb_strlen($title)<5||!in_array($severity,['low','medium','high','critical'],true))throw new RuntimeException('Incident title and severity are required.');
            $reference=dental_privacy_reference('INC');
            $discovered=dental_privacy_clean_datetime($_POST['discovered_at']??null)?:date('Y-m-d H:i:s');
            $stmt=$pdo->prepare('INSERT INTO `' . dental_privacy_incidents_table() . '` (branch_id,incident_reference,title,severity,status,occurred_at,discovered_at,affected_subjects_estimate,data_categories,containment_actions,risk_assessment,notification_required,authority_notification_due_at,patient_notification_due_at,assigned_user_id,created_by,created_at,updated_at) VALUES (?,?,?,? ,"open",?,?,?,?,?,?,?,?,?,?,?,NOW(),NOW())');
            $notification=trim((string)($_POST['notification_required']??'unknown'));if(!in_array($notification,['unknown','yes','no'],true))$notification='unknown';
            $stmt->execute([$branchId,$reference,$title,$severity,dental_privacy_clean_datetime($_POST['occurred_at']??null),$discovered,max(0,(int)($_POST['affected_subjects_estimate']??0)),trim((string)($_POST['data_categories']??'')),trim((string)($_POST['containment_actions']??'')),trim((string)($_POST['risk_assessment']??'')),$notification,dental_privacy_clean_datetime($_POST['authority_notification_due_at']??null),dental_privacy_clean_datetime($_POST['patient_notification_due_at']??null),current_user()['id']??null,current_user()['id']??null]);
            $id=(int)$pdo->lastInsertId();
            audit_required('privacy_incident_created','privacy_incident',$id,['branch_id'=>$branchId,'reference'=>$reference,'severity'=>$severity,'notification_required'=>$notification]);
            flash('success','Privacy incident '.$reference.' recorded.');
        } elseif ($action === 'update_incident') {
            require_permission('privacy.incidents.manage', ['super_admin','clinic_admin']);
            $id=(int)($_POST['id']??0);$status=trim((string)($_POST['status']??''));
            $allowed=['open','contained','investigating','notification_pending','monitoring','closed','false_positive'];
            if($id<1||!in_array($status,$allowed,true))throw new RuntimeException('The incident update is invalid.');
            [$where,$args]=$branchFilter();
            $read=$pdo->prepare('SELECT * FROM `' . dental_privacy_incidents_table() . '` WHERE id=?'.($where!==''?' AND branch_id=?':''));
            $read->execute(array_merge([$id],$args));$old=$read->fetch();if(!$old)throw new RuntimeException('The incident was not found in your branch scope.');
            $closed=in_array($status,['closed','false_positive'],true)?date('Y-m-d H:i:s'):null;
            $stmt=$pdo->prepare('UPDATE `' . dental_privacy_incidents_table() . '` SET status=?,containment_actions=?,risk_assessment=?,closed_at=?,updated_at=NOW() WHERE id=?');
            $stmt->execute([$status,trim((string)($_POST['containment_actions']??$old['containment_actions'])),trim((string)($_POST['risk_assessment']??$old['risk_assessment'])),$closed,$id]);
            audit_required('privacy_incident_updated','privacy_incident',$id,['status'=>$status],['status'=>$old['status']]);
            flash('success','Privacy incident updated.');
        } else {
            throw new RuntimeException('The privacy-governance action was not recognized.');
        }
    } catch (Throwable $exception) {
        flash('error',$exception->getMessage());
    }
    header('Location: privacy_governance.php');
    exit;
}

$branches=[];$processing=[];$retention=[];$requests=[];$incidents=[];$snapshots=[];$counts=['requests_open'=>0,'incidents_open'=>0,'processing_active'=>0,'retention_active'=>0];
$integrity=$schemaReady?audit_integrity_summary(1000):['ready'=>false,'invalid'=>0,'broken_links'=>0,'head_mismatches'=>0,'checked'=>0,'latest_chain_hash'=>''];
if($schemaReady){
    try{$branches=$pdo->query('SELECT id,name FROM `' . table('branches') . '` WHERE is_active=1 ORDER BY name')->fetchAll();}catch(Throwable){}
    $counts=dental_privacy_status_counts();
    [$where,$args]=$branchFilter();
    foreach([
        'processing'=>['SELECT * FROM `'.dental_privacy_processing_table().'`'.$where.' ORDER BY id DESC LIMIT 50',$args],
        'retention'=>['SELECT * FROM `'.dental_privacy_retention_table().'`'.$where.' ORDER BY id DESC LIMIT 50',$args],
        'requests'=>['SELECT * FROM `'.dental_privacy_requests_table().'`'.$where.' ORDER BY id DESC LIMIT 100',$args],
        'incidents'=>['SELECT * FROM `'.dental_privacy_incidents_table().'`'.$where.' ORDER BY id DESC LIMIT 100',$args],
    ] as $name=>$query){$stmt=$pdo->prepare($query[0]);$stmt->execute($query[1]);$$name=$stmt->fetchAll();}
    $snapshots=$pdo->query('SELECT s.*,u.name verified_by_name FROM `' . dental_audit_integrity_snapshots_table() . '` s LEFT JOIN `' . table('users') . '` u ON u.id=s.verified_by ORDER BY s.id DESC LIMIT 20')->fetchAll();
}

render_header('Privacy & Audit Center');
?>
<section class="admin-hero card"><div><span class="eyebrow">Accountability and evidence</span><h2>Privacy &amp; Audit Center</h2><p>Track processing purposes, retention rules, individual-rights requests, privacy incidents, and cryptographically linked audit evidence. This supports governance; it does not replace jurisdiction-specific legal review.</p></div><div class="admin-hero-icon"><?=dental_icon('shield')?></div></section>
<?php if(!$schemaReady): ?><div class="alert warning"><strong>Database update required.</strong> Apply v0.9.0.6 before using this center.</div><?php if(superuser_primary_workspace()):?><a class="btn primary" href="system_setup.php?tab=updates">Open Updates &amp; Database</a><?php endif; ?><?php else: ?>
<section class="stats mini-stats">
<?php stat_card('Open rights requests',(int)$counts['requests_open'],'Identity, access, correction, portability, restriction, objection, or deletion workflow'); ?>
<?php stat_card('Open privacy incidents',(int)$counts['incidents_open'],'Containment, risk assessment, and notification decision'); ?>
<?php stat_card('Audit integrity',($integrity['ready']??false)&&!(int)$integrity['invalid']&&!(int)$integrity['broken_links']&&!(int)$integrity['head_mismatches']?'Verified':'Review required',(int)($integrity['checked']??0).' recent records checked'); ?>
<?php stat_card('Active processing records',(int)$counts['processing_active'],(int)$counts['retention_active'].' active retention rules'); ?>
</section>

<section class="card"><div class="card-head"><div><h2>Audit-chain verification</h2><p>Every new protected audit event is linked to the preceding event for its branch or global chain. A modified, removed, reordered, or inserted chained record is detectable.</p></div><div class="status-actions"><?php if($canVerifyAudit):?><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="verify_audit"><button class="btn primary" type="submit">Verify and save snapshot</button></form><?php endif;?><?php if($canExportAudit):?><a class="btn ghost" href="privacy_governance.php?export=audit_manifest">Export integrity manifest</a><?php endif;?></div></div>
<div class="table-wrap"><table><thead><tr><th>Checked</th><th>Valid</th><th>Invalid</th><th>Broken links</th><th>Head mismatch</th><th>Latest chain hash</th></tr></thead><tbody><tr><td><?=(int)($integrity['checked']??0)?></td><td><?=(int)($integrity['valid']??0)?></td><td><?=(int)($integrity['invalid']??0)?></td><td><?=(int)($integrity['broken_links']??0)?></td><td><?=(int)($integrity['head_mismatches']??0)?></td><td><code><?=e(substr((string)($integrity['latest_chain_hash']??''),0,24))?><?=!empty($integrity['latest_chain_hash'])?'…':''?></code></td></tr></tbody></table></div>
<?php if($snapshots):?><details><summary>Saved verification snapshots</summary><div class="table-wrap"><table><thead><tr><th>Time</th><th>Status</th><th>Rows</th><th>Problems</th><th>Verified by</th></tr></thead><tbody><?php foreach($snapshots as $row):?><tr><td><?=e((string)$row['verified_at'])?></td><td><span class="badge <?=$row['status']==='verified'?'success':'danger'?>"><?=e((string)$row['status'])?></span></td><td><?=(int)$row['checked_rows']?></td><td><?=((int)$row['invalid_rows']+(int)$row['broken_links']+(int)$row['head_mismatches'])?></td><td><?=e((string)($row['verified_by_name']??'System'))?></td></tr><?php endforeach;?></tbody></table></div></details><?php endif;?>
</section>

<div class="grid two">
<?php if($canGovernance):?><section class="card"><div class="card-head"><div><h2>Record a processing activity</h2><p>Document why personal or health information is processed and who receives it.</p></div></div><form method="post" class="form-grid"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="create_processing"><?php if($scopeBranch===null):?><label>Branch<select name="branch_id"><option value="0">Organization-wide</option><?php foreach($branches as $branch):?><option value="<?=(int)$branch['id']?>"><?=e((string)$branch['name'])?></option><?php endforeach;?></select></label><?php endif;?><label>Activity title<input name="title" maxlength="190" required></label><label class="full">Purpose<textarea name="purpose" required></textarea></label><label>Data categories<textarea name="data_categories" placeholder="Identity, contact, dental chart, prescriptions, billing"></textarea></label><label>Data subjects<textarea name="data_subjects" placeholder="Patients, guardians, staff"></textarea></label><label>Legal basis<input name="legal_basis" maxlength="500" required></label><label>Recipients<textarea name="recipients"></textarea></label><label>International transfer<textarea name="international_transfer" placeholder="None, or destination and mechanism"></textarea></label><label>Safeguards<textarea name="safeguards"></textarea></label><label>Review due<input type="date" name="review_due_at"></label><div class="full"><button class="btn primary" type="submit">Record activity</button></div></form></section>
<section class="card"><div class="card-head"><div><h2>Add a retention rule</h2><p>Retention periods must be confirmed against applicable clinical, tax, employment, and privacy requirements.</p></div></div><form method="post" class="form-grid"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="create_retention"><?php if($scopeBranch===null):?><label>Branch<select name="branch_id"><option value="0">Organization-wide</option><?php foreach($branches as $branch):?><option value="<?=(int)$branch['id']?>"><?=e((string)$branch['name'])?></option><?php endforeach;?></select></label><?php endif;?><label>Record category<input name="record_category" required></label><label>Retention months<input type="number" min="1" max="1200" name="retention_months" required></label><label>Trigger event<input name="trigger_event" value="Record closure"></label><label>Legal basis<input name="legal_basis"></label><label>Disposition action<input name="disposition_action" value="Secure deletion or anonymization"></label><label>Review due<input type="date" name="review_due_at"></label><label class="checkbox"><input type="checkbox" name="legal_hold_allowed" value="1" checked> Legal hold can suspend disposal</label><div class="full"><button class="btn primary" type="submit">Add retention rule</button></div></form></section><?php endif;?>
</div>

<div class="grid two">
<?php if($canRequests):?><section class="card"><div class="card-head"><div><h2>Register a privacy-rights request</h2><p>Track identity verification, due dates, action taken, and completion evidence.</p></div></div><form method="post" class="form-grid"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="create_request"><?php if($scopeBranch===null):?><label>Branch<select name="branch_id"><?php foreach($branches as $branch):?><option value="<?=(int)$branch['id']?>"><?=e((string)$branch['name'])?></option><?php endforeach;?></select></label><?php endif;?><label>Requester name<input name="requester_name" required></label><label>Contact<input name="requester_contact"></label><label>Patient ID, when linked<input type="number" min="1" name="patient_id"></label><label>Request type<select name="request_type"><option value="access">Access</option><option value="rectification">Rectification</option><option value="restriction">Restriction</option><option value="portability">Portability</option><option value="objection">Objection</option><option value="erasure">Erasure/deletion review</option><option value="other">Other</option></select></label><label>Received<input type="date" name="received_at" value="<?=date('Y-m-d')?>"></label><label>Due date<input type="date" name="due_at" value="<?=date('Y-m-d',strtotime('+30 days'))?>"></label><label class="full">Notes<textarea name="notes"></textarea></label><div class="full"><button class="btn primary" type="submit">Register request</button></div></form></section><?php endif;?>
<?php if($canIncidents):?><section class="card"><div class="card-head"><div><h2>Register a privacy incident</h2><p>Record containment and risk decisions immediately. Do not wait for the investigation to finish.</p></div></div><form method="post" class="form-grid"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="create_incident"><?php if($scopeBranch===null):?><label>Branch<select name="branch_id"><?php foreach($branches as $branch):?><option value="<?=(int)$branch['id']?>"><?=e((string)$branch['name'])?></option><?php endforeach;?></select></label><?php endif;?><label>Incident title<input name="title" required></label><label>Severity<select name="severity"><option>low</option><option selected>medium</option><option>high</option><option>critical</option></select></label><label>Occurred at<input type="datetime-local" name="occurred_at"></label><label>Discovered at<input type="datetime-local" name="discovered_at" value="<?=date('Y-m-d\TH:i')?>"></label><label>Affected people estimate<input type="number" min="0" name="affected_subjects_estimate" value="0"></label><label>Notification decision<select name="notification_required"><option value="unknown">Undetermined</option><option value="yes">Required</option><option value="no">Not required</option></select></label><label>Authority notification due<input type="datetime-local" name="authority_notification_due_at"></label><label>Affected-person notification due<input type="datetime-local" name="patient_notification_due_at"></label><label>Data categories<textarea name="data_categories"></textarea></label><label>Immediate containment<textarea name="containment_actions"></textarea></label><label class="full">Initial risk assessment<textarea name="risk_assessment"></textarea></label><div class="full"><button class="btn danger" type="submit">Register incident</button></div></form></section><?php endif;?>
</div>

<section class="card"><div class="card-head"><div><h2>Rights-request register</h2><p>Overdue items remain visible until completed, rejected with a documented basis, or withdrawn.</p></div></div><?php if(!$requests):?><p class="muted">No privacy-rights requests recorded.</p><?php else:?><div class="table-wrap"><table><thead><tr><th>Reference</th><th>Requester</th><th>Type / due</th><th>Status</th><th>Update</th></tr></thead><tbody><?php foreach($requests as $row):?><tr><td><strong><?=e((string)$row['request_reference'])?></strong><small><?=e((string)$row['received_at'])?></small></td><td><?=e((string)$row['requester_name'])?><small><?=e((string)$row['requester_contact'])?></small></td><td><?=e((string)$row['request_type'])?><small class="<?=strtotime((string)$row['due_at'])<time()&&!in_array($row['status'],['completed','rejected','withdrawn'],true)?'text-danger':''?>">Due <?=e((string)$row['due_at'])?></small></td><td><span class="badge neutral"><?=e((string)$row['status'])?></span><small>Identity: <?=e((string)$row['identity_verification_status'])?></small></td><td><?php if($canRequests):?><form method="post" class="compact-form"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="update_request"><input type="hidden" name="id" value="<?=(int)$row['id']?>"><select name="status"><?php foreach(['received','identity_check','in_progress','waiting_for_requester','completed','rejected','withdrawn'] as $status):?><option value="<?=$status?>" <?=$row['status']===$status?'selected':''?>><?=$status?></option><?php endforeach;?></select><select name="identity_verification_status"><?php foreach(['pending','verified','failed','not_required'] as $status):?><option value="<?=$status?>" <?=$row['identity_verification_status']===$status?'selected':''?>><?=$status?></option><?php endforeach;?></select><input name="outcome_summary" value="<?=e((string)$row['outcome_summary'])?>" placeholder="Outcome or reason"><button class="btn compact" type="submit">Save</button></form><?php endif;?></td></tr><?php endforeach;?></tbody></table></div><?php endif;?></section>

<section class="card"><div class="card-head"><div><h2>Privacy-incident register</h2><p>Closing an incident requires documented containment and risk assessment. Notification decisions remain a legal/governance determination.</p></div></div><?php if(!$incidents):?><p class="muted">No privacy incidents recorded.</p><?php else:?><div class="table-wrap"><table><thead><tr><th>Reference</th><th>Incident</th><th>Severity</th><th>Status</th><th>Notification</th><th>Update</th></tr></thead><tbody><?php foreach($incidents as $row):?><tr><td><strong><?=e((string)$row['incident_reference'])?></strong><small><?=e((string)$row['discovered_at'])?></small></td><td><?=e((string)$row['title'])?><small>Affected estimate: <?=(int)$row['affected_subjects_estimate']?></small></td><td><span class="badge <?=$row['severity']==='critical'?'danger':($row['severity']==='high'?'warning':'neutral')?>"><?=e((string)$row['severity'])?></span></td><td><?=e((string)$row['status'])?></td><td><?=e((string)$row['notification_required'])?><small><?=e((string)($row['authority_notification_due_at']??''))?></small></td><td><?php if($canIncidents):?><form method="post" class="compact-form"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="update_incident"><input type="hidden" name="id" value="<?=(int)$row['id']?>"><select name="status"><?php foreach(['open','contained','investigating','notification_pending','monitoring','closed','false_positive'] as $status):?><option value="<?=$status?>" <?=$row['status']===$status?'selected':''?>><?=$status?></option><?php endforeach;?></select><input name="containment_actions" value="<?=e((string)$row['containment_actions'])?>" placeholder="Containment"><input name="risk_assessment" value="<?=e((string)$row['risk_assessment'])?>" placeholder="Risk assessment"><button class="btn compact" type="submit">Save</button></form><?php endif;?></td></tr><?php endforeach;?></tbody></table></div><?php endif;?></section>

<section class="card"><div class="card-head"><div><h2>Processing and retention inventory</h2></div></div><div class="grid two"><div><h3>Processing activities</h3><?php if(!$processing):?><p class="muted">No processing activities recorded.</p><?php else:?><div class="table-wrap"><table><thead><tr><th>Activity</th><th>Purpose</th><th>Legal basis</th><th>Review</th></tr></thead><tbody><?php foreach($processing as $row):?><tr><td><?=e((string)$row['title'])?></td><td><?=e((string)$row['purpose'])?></td><td><?=e((string)$row['legal_basis'])?></td><td><?=e((string)$row['review_due_at'])?></td></tr><?php endforeach;?></tbody></table></div><?php endif;?></div><div><h3>Retention rules</h3><?php if(!$retention):?><p class="muted">No retention rules recorded.</p><?php else:?><div class="table-wrap"><table><thead><tr><th>Category</th><th>Period</th><th>Trigger</th><th>Disposition</th></tr></thead><tbody><?php foreach($retention as $row):?><tr><td><?=e((string)$row['record_category'])?></td><td><?=(int)$row['retention_months']?> months</td><td><?=e((string)$row['trigger_event'])?></td><td><?=e((string)$row['disposition_action'])?></td></tr><?php endforeach;?></tbody></table></div><?php endif;?></div></div></section>
<?php endif; render_footer();
