<?php
// ---------------------------------------------------------------------
// Shared helpers for the Employee Onboarding module. Plain functions
// (no namespace) so they're easy to require() from controllers/views,
// matching the style of app/Core/KpiFieldLabels.php etc.
// ---------------------------------------------------------------------

function onb_fmt_mdy(?string $date): string {
    if (!$date) return '';
    $ts = strtotime($date);
    return $ts ? date('m/d/Y', $ts) : $date;
}

function onb_new_token(): string {
    return bin2hex(random_bytes(6));
}

function onb_full_name(array $h): string {
    return trim(implode(' ', array_filter([$h['first'] ?? '', $h['middle'] ?? '', $h['last'] ?? ''])));
}

function onb_city_state_zip(array $h): string {
    $s = $h['city'] ?? '';
    if (!empty($h['state'])) $s .= ($s ? ', ' : '') . $h['state'];
    if (!empty($h['zip'])) $s .= ' ' . $h['zip'];
    return $s;
}

function onb_pay_rate_amt(array $h): string {
    $v = $h['pay_rate'] ?? '';
    $v = preg_replace('/\s*\/\s*(hr|hour)s?\b/i', '', $v);
    return trim(ltrim($v, '$'));
}

// Every hire gets a real folder on disk:
// storage/onboarding/{Name} [{token6}]/{HR Form|Phase A|I-9|Phase B|W-4|DE4|WOTC|Signatures|Uploaded Documents}
function onb_employee_folder(array $h): string {
    $cfg = require __DIR__ . '/../../config/config.php';
    $base = rtrim($cfg['storage_path'] ?? (__DIR__ . '/../../storage'), '/');
    $name = trim(($h['first'] ?? '') . ' ' . ($h['last'] ?? ''));
    $name = $name !== '' ? $name : ('Unnamed-' . $h['token']);
    $safe = preg_replace('/[\\\\\/:*?"<>|]/', '-', $name);
    $folder = $base . '/onboarding/' . $safe . ' [' . substr($h['token'], -6) . ']';
    foreach (['', '/HR Form', '/Phase A', '/I-9', '/Phase B', '/W-4', '/DE4', '/WOTC', '/Signatures', '/Uploaded Documents'] as $sub) {
        $dir = $folder . $sub;
        if (!is_dir($dir)) @mkdir($dir, 0755, true);
    }
    return $folder;
}

function onb_status_label(string $status): string {
    $map = [
        'New' => 'New', 'A_sent' => 'Phase A sent', 'A_done' => 'Phase A done · I-9 due',
        'I9_done' => 'I-9 verified', 'Training' => 'Training complete', 'B_sent' => 'Phase B sent', 'Final' => 'Finalized',
    ];
    return $map[$status] ?? $status;
}

function onb_link(string $token, string $phase): string {
    $cfg = require __DIR__ . '/../../config/config.php';
    $base = rtrim($cfg['app_url'] ?? '', '/');
    return $base . '/onboarding/apply?token=' . urlencode($token) . '&phase=' . urlencode($phase);
}

// Notifies every staff member assigned to the Employee Onboarding project
// (via user_projects, the same table Super Admin already uses to grant
// access) plus all super admins — so this never needs to hardcode
// "Rachel" and automatically covers anyone given access later.
// Minimal fallback PDF writer (no external library needed) for HR Form /
// Phase A / Phase B / I-9 summary snapshots. Government forms (W-4, DE4,
// I-9, WOTC) are filled separately via the real templates in PdfFill.php.
function pdf_escape_str(string $s): string {
    return str_replace(['\\', '(', ')'], ['\\\\', '\\(', '\\)'], $s);
}

// Minimal fallback PDF writer (no external library needed) for HR Form /
// Phase A / Phase B / I-9 summary snapshots. Government forms (W-4, DE4,
// I-9, WOTC) are filled separately via the real templates in PdfFill.php.
// Writes proper multi-line, paginated, structurally-valid PDF (real xref
// table) -- verified with qpdf --check and pdftotext against real output.
function generate_simple_pdf_local(string $title, array $fields, ?array $signature, string $outPath): void {
    $lines = [];
    $lines[] = ['text' => $title, 'size' => 14, 'gap_after' => 10];
    foreach ($fields as $k => $v) {
        if (is_array($v)) continue;
        $label = ucwords(str_replace('_', ' ', $k));
        $val = (string)$v;
        $full = $label . ': ' . ($val === '' ? '(blank)' : $val);
        foreach (str_split($full, 95) as $chunk) {
            $lines[] = ['text' => $chunk, 'size' => 10, 'gap_after' => 2];
        }
    }
    if ($signature) {
        $lines[] = ['text' => '', 'size' => 10, 'gap_after' => 6];
        $lines[] = ['text' => 'Signed by ' . ($signature['name'] ?? '') . ' on ' . ($signature['ts'] ?? ''), 'size' => 10, 'gap_after' => 0];
    }
    pdf_write_lines($lines, $outPath);
}

// Renders one PDF section per form (title header + its own fields + its own
// signature line), in the order supplied, instead of one flat merged dump.
// $forms is a list of ['key'=>, 'title'=>, 'fields'=>[...], 'signedBy'=>, 'signedAt'=>].
function generate_multiform_pdf_local(string $docTitle, array $forms, string $outPath): void {
    $lines = [];
    $lines[] = ['text' => $docTitle, 'size' => 16, 'gap_after' => 14];
    $n = 0;
    foreach ($forms as $form) {
        $n++;
        $title = (string)($form['title'] ?? $form['key'] ?? "Form $n");
        $lines[] = ['text' => "Form $n — $title", 'size' => 13, 'gap_after' => 8, 'new_page' => $n > 1];
        $fields = $form['fields'] ?? [];
        if (!$fields) {
            $lines[] = ['text' => '(no fillable fields on this form)', 'size' => 10, 'gap_after' => 2];
        }
        foreach ($fields as $k => $v) {
            if (is_array($v)) continue;
            $label = ucwords(str_replace('_', ' ', (string)$k));
            $val = (string)$v;
            $full = $label . ': ' . ($val === '' ? '(blank)' : $val);
            foreach (str_split($full, 95) as $chunk) {
                $lines[] = ['text' => $chunk, 'size' => 10, 'gap_after' => 2];
            }
        }
        $signedBy = $form['signedBy'] ?? '';
        if ($signedBy !== '') {
            $lines[] = ['text' => '', 'size' => 10, 'gap_after' => 4];
            $lines[] = ['text' => 'Signed by ' . $signedBy . ' on ' . ($form['signedAt'] ?? ''), 'size' => 10, 'gap_after' => 0];
        }
        $lines[] = ['text' => '', 'size' => 8, 'gap_after' => 10];
    }
    pdf_write_lines($lines, $outPath);
}

// Shared low-level writer: lays out an array of {text,size,gap_after,new_page?}
// lines into a real, structurally-valid multi-page PDF (proper xref table).
// Extracted from the original generate_simple_pdf_local so both the flat
// single-section dump and the new per-form multi-section renderer share the
// exact same page/pagination/PDF-object logic.
function pdf_write_lines(array $lines, string $outPath): void {
    $dir = dirname($outPath);
    if (!is_dir($dir)) @mkdir($dir, 0755, true);

    $pageHeight = 792; $topY = 740; $bottomLimit = 40;
    $pages = []; $current = []; $y = $topY;
    foreach ($lines as $ln) {
        $lineHeight = $ln['size'] + 4;
        if ((!empty($ln['new_page']) && $current) || $y - $lineHeight < $bottomLimit) { $pages[] = $current; $current = []; $y = $topY; }
        $current[] = ['text' => $ln['text'], 'size' => $ln['size'], 'y' => $y];
        $y -= $lineHeight + $ln['gap_after'];
    }
    if ($current) $pages[] = $current;
    if (!$pages) $pages[] = [];

    $pageCount = count($pages);
    $fontObjNum = 3 + $pageCount * 2;
    $kids = [];
    $nextObjNum = 3;
    $objBodies = [];

    foreach ($pages as $pageLines) {
        $contentObjNum = $nextObjNum++;
        $pageObjNum = $nextObjNum++;
        $stream = '';
        foreach ($pageLines as $pl) {
            $escaped = pdf_escape_str($pl['text']);
            $stream .= "BT /F1 {$pl['size']} Tf 40 {$pl['y']} Td ({$escaped}) Tj ET\n";
        }
        $objBodies[$contentObjNum] = "<</Length " . strlen($stream) . ">>\nstream\n{$stream}endstream";
        $objBodies[$pageObjNum] = "<</Type/Page/Parent 2 0 R/MediaBox[0 0 612 {$pageHeight}]/Resources<</Font<</F1 {$fontObjNum} 0 R>>>>/Contents {$contentObjNum} 0 R>>";
        $kids[] = "{$pageObjNum} 0 R";
    }
    $objBodies[1] = "<</Type/Catalog/Pages 2 0 R>>";
    $objBodies[2] = "<</Type/Pages/Kids[" . implode(' ', $kids) . "]/Count {$pageCount}>>";
    $objBodies[$fontObjNum] = "<</Type/Font/Subtype/Type1/BaseFont/Helvetica>>";

    ksort($objBodies);
    $totalObjs = max(array_keys($objBodies));

    $pdf = "%PDF-1.4\n";
    $offsets = [0 => 0];
    for ($n = 1; $n <= $totalObjs; $n++) {
        $offsets[$n] = strlen($pdf);
        $pdf .= isset($objBodies[$n]) ? "{$n} 0 obj\n{$objBodies[$n]}\nendobj\n" : "{$n} 0 obj\n<<>>\nendobj\n";
    }
    $xrefOffset = strlen($pdf);
    $pdf .= "xref\n0 " . ($totalObjs + 1) . "\n0000000000 65535 f \n";
    for ($n = 1; $n <= $totalObjs; $n++) { $pdf .= sprintf("%010d 00000 n \n", $offsets[$n]); }
    $pdf .= "trailer\n<</Size " . ($totalObjs + 1) . "/Root 1 0 R>>\nstartxref\n{$xrefOffset}\n%%EOF";

    file_put_contents($outPath, $pdf);
}

function onb_notify_reviewers(string $title, string $message, string $link): void {
    $db = \App\Core\Database::connection();

    $stmt = $db->query(
        "SELECT DISTINCT up.user_type, up.user_id
         FROM user_projects up
         JOIN projects p ON p.id = up.project_id
         WHERE p.code = 'employee_onboarding'"
    );
    $recipients = $stmt->fetchAll();

    // Also notify every super admin (they always have implicit access).
    // NOTE: the `superadmins` table has no `is_active` column, so every
    // row here is treated as active — this matches actual behavior since
    // there's currently no way to deactivate a super admin account.
    $sa = $db->query("SELECT id FROM superadmins")->fetchAll();
    foreach ($sa as $row) {
        $recipients[] = ['user_type' => 'superadmin', 'user_id' => $row['id']];
    }

    $insert = $db->prepare(
        "INSERT INTO notifications (user_type, user_id, title, message, link) VALUES (?,?,?,?,?)"
    );
    $seen = [];
    foreach ($recipients as $r) {
        $key = $r['user_type'] . ':' . $r['user_id'];
        if (isset($seen[$key])) continue; // de-dupe if a super admin is also directly assigned
        $seen[$key] = true;
        $insert->execute([$r['user_type'], $r['user_id'], $title, $message, $link]);
    }
}
