<?php
/**
 * Medmecs MIS - master configuration.
 * Edit DB credentials and SMTP details here. No other file should
 * hard-code these values.
 */

// ---------- App ----------
define('APP_NAME',          'Medmecs MIS');
// Canonical STAMPING timezone — every record (add/edit/delete) is stamped in US Eastern Time (EST/EDT, DST-aware).
// The DB session time_zone is pinned to the matching Eastern offset in db.php so NOW()/TIMESTAMP writes agree.
// Reports can be VIEWED in IST via the per-user toggle (app_display_tz()); the stamp is always Eastern.
define('APP_TIMEZONE',      'America/New_York');

/* ---------------------------------------------------------------------------
 * Environment auto-detection — ONE codebase runs in both places, no edits
 * needed when you deploy.
 *   Local dev   : Windows / XAMPP   (DIRECTORY_SEPARATOR === '\')
 *   Live server : Linux / cPanel
 * ------------------------------------------------------------------------- */
define('IS_LOCAL', DIRECTORY_SEPARATOR === '\\');

if (IS_LOCAL) {
    // ===== Local XAMPP =====
    define('APP_DEBUG',    true);
    // Default is the XAMPP path; override with the MEDMECS_BASE_URL env var when serving
    // local dev from a different origin (e.g. `php -S 127.0.0.1:8742`). Prod is unaffected.
    define('APP_BASE_URL', getenv('MEDMECS_BASE_URL') ?: 'http://localhost/medmecs');   // no trailing slash
    define('DB_HOST',      '127.0.0.1');
    define('DB_PORT',      3306);
    define('DB_NAME',      'medmecs_mis');
    define('DB_USER',      'root');
    define('DB_PASS',      '');                              // XAMPP default
} else {
    // ===== Live server (cPanel / GlobeHost) =====
    // Debug OFF in production: raw errors (stack traces, server paths, SQL) are never shown to visitors —
    // they still log to the DB / error log. Flip to true ONLY for short-lived live debugging.
    define('APP_DEBUG',    false);

    // Base URL is derived from the request, so the app works on whatever domain
    // points at public_html — nothing to hard-code here.
    $__https  = (!empty($_SERVER['HTTPS']) && strtolower((string) $_SERVER['HTTPS']) !== 'off')
             || (($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https');
    $__host   = $_SERVER['HTTP_HOST'] ?? 'localhost';
    // The app may sit at the domain root OR in a subfolder (e.g. /medmecs). Derive the
    // subfolder from where the app lives under DOCUMENT_ROOT so links are correct either way.
    $__docroot = str_replace('\\', '/', rtrim((string) realpath($_SERVER['DOCUMENT_ROOT'] ?? ''), '/'));
    $__approot = str_replace('\\', '/', dirname(__DIR__));
    $__sub     = ($__docroot !== '' && strpos($__approot, $__docroot) === 0)
               ? rtrim(substr($__approot, strlen($__docroot)), '/')
               : '';
    define('APP_BASE_URL', ($__https ? 'https' : 'http') . '://' . $__host . $__sub);

    define('DB_HOST',      'localhost');                     // cPanel MySQL via UNIX socket
    define('DB_PORT',      3306);
    define('DB_NAME',      'medmecsa_mis');
    define('DB_USER',      'medmecsa_mis');
    define('DB_PASS',      'medmecsa_mis');
}

// ---------- Security ----------
define('PASSWORD_MIN_LENGTH',     10);
define('PASSWORD_REQUIRE_MIXED',  true);
define('PASSWORD_REQUIRE_NUMBER', true);
define('PASSWORD_REQUIRE_SYMBOL', true);
define('LOGIN_MAX_ATTEMPTS',      5);
define('LOGIN_LOCKOUT_MINUTES',   15);

// ---------- Sessions ----------
// Internal idle timeout is generous: a coder can spend a long time on a single chart
// (the coding view is entirely client-side until "Save"), and a short idle window logged
// them out mid-chart — the "Session expired" on Save. A keepalive ping refreshes activity
// while a chart is open; this is the safety ceiling.
define('SESSION_TIMEOUT_INTERNAL_MIN', 240);
define('SESSION_TIMEOUT_CLIENT_MIN',   30);
define('SESSION_NAME',                 'medmecs_sid');
// Session-IP rebinding policy. Strict full-IP match logs users out whenever their
// outbound IP rotates (CGNAT / mobile / cPanel-behind-LB / cloud proxy) — typically
// observed as "logout on Save". Options:
//   'strict'   — require exact IP match (most secure, breaks under IP rotation)
//   'prefix24' — same /24 (first 3 octets) is OK; e.g. 1.2.3.X always matches 1.2.3.Y
//   'prefix16' — same /16 (first 2 octets) is OK
//   'off'      — don't check IP at all (UA-hash + CSRF + idle timeout still apply)
// Live host (cPanel/GlobeHost behind a proxy/CDN) rotates REMOTE_ADDR between requests, which
// caused "logout / Session ended on Save". IP binding is OFF on live (UA-hash + CSRF + idle still
// apply); local dev keeps /24 binding. Override here if you want it stricter on live.
if (!defined('SESSION_IP_BIND')) define('SESSION_IP_BIND', IS_LOCAL ? 'prefix24' : 'off');

// ---------- Uploads ----------
define('UPLOAD_MAX_BYTES',    100 * 1024 * 1024);             // 100 MB
define('UPLOAD_ALLOWED_EXT',  ['xlsx','xls','csv']);

/* ---------- Persistent PHI upload storage (billing sheets) ----------
 * Uploaded billing-sheet files are RUNTIME data and are deliberately kept OUT of the deploy zip.
 * To guarantee they SURVIVE every zip re-deploy, store them OUTSIDE the app folder you replace:
 *   - Local : <project>/storage/uploads/billing-sheets
 *   - Live  : a "medmecs_data" folder ABOVE public_html — i.e. OUTSIDE the web root (so PHI is never
 *             web-served) AND OUTSIDE the deployed app folder (so replacing the medmecs zip never
 *             touches it). Resolved from DOCUMENT_ROOT's parent (your cPanel account home).
 *             On this account that resolves to:  /home2/medmecs1/medmecs_data/billing-sheets
 * If your hosting layout differs, hard-code an absolute path here instead, e.g.:
 *     define('BILLING_SHEETS_DIR', '/home2/medmecs1/medmecs_data/billing-sheets');
 * The Billing-sheets upload page shows the resolved path + whether it is writable, so you can confirm
 * at a glance after deploying. */
if (!defined('BILLING_SHEETS_DIR')) {
    if (IS_LOCAL) {
        define('BILLING_SHEETS_DIR', dirname(__DIR__) . '/storage/uploads/billing-sheets');
    } else {
        $__docroot = rtrim(str_replace('\\', '/', (string) ($_SERVER['DOCUMENT_ROOT'] ?? '')), '/');
        $__home    = $__docroot !== '' ? dirname($__docroot) : dirname(__DIR__, 1);   // …/home (above public_html)
        define('BILLING_SHEETS_DIR', $__home . '/medmecs_data/billing-sheets');
    }
}

// ---------- SMTP (configure when you wire scheduled emails) ----------
define('SMTP_HOST',           '');
define('SMTP_PORT',           587);
define('SMTP_USER',           '');
define('SMTP_PASS',           '');
define('SMTP_FROM_ADDR',      'no-reply@medmecs.local');
define('SMTP_FROM_NAME',      APP_NAME);

// ---------- Runtime ----------
date_default_timezone_set(APP_TIMEZONE);
ini_set('display_errors', APP_DEBUG ? '1' : '0');
ini_set('log_errors', '1');
error_reporting(E_ALL);

// Common helpers
require_once __DIR__ . '/db.php';
require_once __DIR__ . '/auth.php';
require_once __DIR__ . '/csrf.php';
require_once __DIR__ . '/audit.php';
require_once __DIR__ . '/helpers.php';
require_once __DIR__ . '/verticals.php'; // data-driven vertical model (shared across all modules)
require_once __DIR__ . '/auto-migrate.php';
require_once __DIR__ . '/error-log.php';
require_once __DIR__ . '/coding.php';   // medical-coding module (engine + migrations)
require_once __DIR__ . '/ar.php';       // AR / Collections inventory-allocation module (engine + migrations)
require_once __DIR__ . '/billing.php';  // Billing workflow module (allocation + biller tagging + RFI-to-coding)

/* ----------------------------------------------------------------------
 * Global error capture - PHP errors and uncaught exceptions are recorded
 * into system_reference_errors so the System Reference Index error tab
 * has live data. Silent catch: never break the page if logging fails.
 * -------------------------------------------------------------------- */
function srx_log_error(string $level, string $message, ?string $file = null, ?int $line = null, ?string $trace = null): void
{
    try {
        $pdo = db();
        // Capture the request URL (with query string) so the page that errored is identifiable.
        $url = ($_SERVER['REQUEST_URI'] ?? '');
        if ($url !== '' && isset($_SERVER['HTTP_HOST'])) $url = $_SERVER['HTTP_HOST'] . $url;
        $pdo->prepare(
            'INSERT INTO system_reference_errors
             (error_level, message, file, line, trace, user_id, ip, url, method, occurred_at, resolved)
             VALUES (?,?,?,?,?,?,?,?,?,NOW(),0)'
        )->execute([
            $level,
            mb_substr($message, 0, 4000),
            $file ? mb_substr($file, 0, 500) : null,
            $line,
            $trace ? mb_substr($trace, 0, 16384) : null,
            $_SESSION['uid'] ?? null,
            $_SERVER['REMOTE_ADDR'] ?? null,
            $url ? mb_substr($url, 0, 500) : null,
            $_SERVER['REQUEST_METHOD'] ?? null,
        ]);
    } catch (Throwable $t) { /* swallow - never block the page */ }
}

set_error_handler(function ($severity, $message, $file, $line) {
    if (!(error_reporting() & $severity)) return false;
    $map = [
        E_ERROR=>'error', E_WARNING=>'warning', E_PARSE=>'critical',
        E_NOTICE=>'notice', E_USER_ERROR=>'error', E_USER_WARNING=>'warning',
        E_USER_NOTICE=>'notice', E_DEPRECATED=>'notice', E_USER_DEPRECATED=>'notice',
    ];
    srx_log_error($map[$severity] ?? 'error', $message, $file, $line);
    return false; // let PHP's default handler run too
});

set_exception_handler(function (Throwable $t) {
    srx_log_error('critical', get_class($t) . ': ' . $t->getMessage(),
        $t->getFile(), $t->getLine(), $t->getTraceAsString());
    if (APP_DEBUG) {
        echo '<pre style="background:#fee;color:#900;padding:16px;font:13px monospace">'
           . htmlspecialchars($t->getMessage() . "\n\n" . $t->getTraceAsString())
           . '</pre>';
    } else {
        http_response_code(500);
        echo '<h2>Something went wrong.</h2>';
    }
    exit;
});

register_shutdown_function(function () {
    $err = error_get_last();
    if ($err && in_array($err['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) {
        srx_log_error('critical', $err['message'], $err['file'], $err['line']);
    }
});
