<?php
/**
 * ajax/submit_hospital_invoice_etims.php
 *
 * eTIMS submission for HOSPITAL invoices (B2B).
 *
 * Tables used (schema-verified):
 *   hospital_invoices          – PK: hinvoice_id
 *   hospital_engagements       – PK: engagement_id
 *   hospital_engagement_items  – FK: engagement_id, cols: item_id, item_type,
 *                                    service_description, etims_item_code,
 *                                    quantity, unit_price, tax_type
 *   external_service_providers – PK: provider_id, cols: provider_name, tax_id,
 *                                    email, phone, physical_address
 *   system_settings            – cols: setting_key, setting_value, category
 *   etims_api_log              – cols: endpoint, request_data, response_data,
 *                                    http_code, success, created_at
 *   activity_log               – cols: user_id, action, module, record_id,
 *                                    record_type, logged_at  ← NOT created_at
 *
 * Queue safety:
 *   etims_result_code = 'PENDING' is committed before the API call.
 *   On failure  → 'ERR'   + etims_result_message.
 *   On success  → '000'   + all eTIMS fields populated.
 */

session_start();
header('Content-Type: application/json');

include '../layouts/dbconn.php';

// ── eTIMS integration class ───────────────────────────────────────────────────
$etims_class = dirname(__DIR__) . '/includes/EtimsIntegration.php';
if (!file_exists($etims_class)) {
    echo json_encode(['success' => false, 'message' => 'EtimsIntegration class not found.']);
    exit();
}
require_once $etims_class;

// ── Auth ──────────────────────────────────────────────────────────────────────
if (empty($_SESSION['user_id'])) {
    echo json_encode(['success' => false, 'message' => 'Unauthorized.']);
    exit();
}

$allowed_roles = ['SUPER_ADMIN', 'HOSPITAL_ADMIN', 'ADMIN', 'ACCOUNTANT',
                  'BILLING_CLERK', 'FINANCE_MANAGER'];
if (empty($_SESSION['role_code']) || !in_array($_SESSION['role_code'], $allowed_roles)) {
    echo json_encode(['success' => false, 'message' => 'Insufficient permissions.']);
    exit();
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    echo json_encode(['success' => false, 'message' => 'POST required.']);
    exit();
}

// ── Input ─────────────────────────────────────────────────────────────────────
$hinvoice_id  = isset($_POST['hinvoice_id'])  ? (int)  $_POST['hinvoice_id']  : 0;
$payment_mode = isset($_POST['payment_mode']) ? trim(  $_POST['payment_mode']): 'Credit';
$is_retry     = !empty($_POST['is_retry']);

if ($hinvoice_id <= 0) {
    echo json_encode(['success' => false, 'message' => 'Invalid hospital invoice ID.']);
    exit();
}

// ── eTIMS guard ───────────────────────────────────────────────────────────────
$etims = new EtimsIntegration($conn);
if (!$etims->isEnabled() && !$etims->isMockMode()) {
    echo json_encode(['success' => false,
                      'message' => 'eTIMS integration is disabled system-wide.']);
    exit();
}

// ── Log helper ────────────────────────────────────────────────────────────────
$log_dir = dirname(__DIR__) . '/logs';
if (!is_dir($log_dir)) {
    @mkdir($log_dir, 0755, true);
}

function hetims_log(string $log_dir, array $data): void
{
    @file_put_contents(
        $log_dir . '/hospital_etims_api.jsonl',
        json_encode($data) . "\n",
        LOCK_EX | FILE_APPEND
    );
}

// ── Helper: write ERR state and commit ───────────────────────────────────────
function hetims_mark_error(mysqli $conn, int $hinvoice_id, string $msg): void
{
    $s = $conn->prepare(
        "UPDATE hospital_invoices
         SET etims_result_code    = 'ERR',
             etims_result_message = ?,
             updated_at           = NOW()
         WHERE hinvoice_id = ?"
    );
    if ($s) {
        $s->bind_param('si', $msg, $hinvoice_id);
        $s->execute();
        $s->close();
    }
    mysqli_commit($conn);
}

// ═════════════════════════════════════════════════════════════════════════════
// MAIN
// ═════════════════════════════════════════════════════════════════════════════
$conn->begin_transaction();
$response = null;   // keeps scope for catch block

try {

    // ── 1. Fetch hospital invoice + provider + engagement ─────────────────────
    $stmt = $conn->prepare("
        SELECT
            hi.hinvoice_id,
            hi.invoice_number,
            hi.engagement_id,
            hi.total_amount,
            hi.status           AS invoice_status,
            hi.etims_submitted,
            hi.etims_invoice_number,
            hi.etims_result_code,
            esp.provider_name,
            esp.tax_id          AS hospital_kra_pin,
            esp.email           AS hospital_email,
            esp.physical_address AS hospital_address,
            esp.phone           AS hospital_phone,
            he.engagement_number,
            he.description      AS engagement_description
        FROM  hospital_invoices hi
        JOIN  external_service_providers esp ON hi.provider_id  = esp.provider_id
        JOIN  hospital_engagements       he  ON hi.engagement_id = he.engagement_id
        WHERE hi.hinvoice_id = ?
    ");
    if (!$stmt) {
        throw new Exception('DB prepare failed: ' . $conn->error);
    }
    $stmt->bind_param('i', $hinvoice_id);
    $stmt->execute();
    $inv = $stmt->get_result()->fetch_assoc();
    $stmt->close();

    if (!$inv) {
        throw new Exception('Hospital invoice not found.');
    }

    // Guard: already submitted (unless explicit retry)
    if (!$is_retry) {
        if (!empty($inv['etims_invoice_number'])) {
            throw new Exception(
                "Invoice already submitted to eTIMS (CU#: {$inv['etims_invoice_number']})."
            );
        }
        if ((int)$inv['etims_submitted'] === 1) {
            throw new Exception('Invoice is already marked as submitted in eTIMS.');
        }
    }

    // KRA PIN is mandatory for B2B hospital invoices
    $hospital_kra_pin = strtoupper(trim($inv['hospital_kra_pin'] ?? ''));
    if ($hospital_kra_pin === '') {
        throw new Exception(
            "Hospital '{$inv['provider_name']}' has no KRA PIN. " .
            "Update the hospital record before submitting to eTIMS."
        );
    }

    // ── 2. Fetch line items ───────────────────────────────────────────────────
    $stmt_items = $conn->prepare(
        "SELECT item_id, item_type, service_description, etims_item_code,
                quantity, unit_price, tax_type
         FROM   hospital_engagement_items
         WHERE  engagement_id = ?
         ORDER  BY item_id ASC"
    );
    if (!$stmt_items) {
        throw new Exception('DB prepare (items) failed: ' . $conn->error);
    }
    $stmt_items->bind_param('i', $inv['engagement_id']);
    $stmt_items->execute();
    $items_res = $stmt_items->get_result();

    if ($items_res->num_rows === 0) {
        throw new Exception('Hospital invoice has no line items.');
    }

    $invoice_items = [];
    $seq = 1;
    while ($row = $items_res->fetch_assoc()) {
        // Prefer stored eTIMS item code; fall back to sequential KE3NTU code
        $item_code = !empty(trim($row['etims_item_code'] ?? ''))
            ? trim($row['etims_item_code'])
            : ('KE3NTU' . str_pad($seq, 5, '0', STR_PAD_LEFT));

        $invoice_items[] = [
            'item_code'       => $item_code,
            'item_name'       => !empty($row['service_description'])
                                     ? $row['service_description']
                                     : ('Hospital Service – ' . $row['item_type']),
            'quantity'        => (int) max(1, $row['quantity']),
            'unit_price'      => (float) $row['unit_price'],
            'tax_type'        => $row['tax_type'] ?? 'D',   // D = Non-VAT (medical default)
            'item_class_code' => '86211900',                 // Medical services HS code
        ];
        $seq++;
    }
    $stmt_items->close();

    // ── 3. Business settings ──────────────────────────────────────────────────
    $biz_res = $conn->query(
        "SELECT setting_key, setting_value
         FROM   system_settings
         WHERE  category    = 'hospital'
           AND  setting_key IN ('hospital_name','hospital_address')"
    );
    $biz_cfg = [];
    if ($biz_res) {
        while ($r = $biz_res->fetch_assoc()) {
            $biz_cfg[$r['setting_key']] = $r['setting_value'];
        }
    }

    $business_name    = $biz_cfg['hospital_name']    ?? 'PRODIGY ENT';
    $business_address = $biz_cfg['hospital_address'] ?? '';

    // ── 4. Mark as PENDING and commit before hitting the API ─────────────────
    //       This sentinel prevents duplicate submissions if the process crashes
    //       mid-flight and is retried.
    $pend = $conn->prepare(
        "UPDATE hospital_invoices
         SET etims_result_code    = 'PENDING',
             etims_result_message = 'Submission in progress',
             updated_at           = NOW()
         WHERE hinvoice_id = ?"
    );
    if (!$pend) {
        throw new Exception('DB prepare (pending) failed: ' . $conn->error);
    }
    $pend->bind_param('i', $hinvoice_id);
    if (!$pend->execute()) {
        throw new Exception('Failed to set PENDING sentinel: ' . $conn->error);
    }
    $pend->close();

    $conn->commit();                    // ← commit PENDING before API call
    $conn->begin_transaction();         // ← new transaction for the result write

    // ── 5. Build payload and call eTIMS ──────────────────────────────────────
    $submit_data = [
        'invoice_number'    => (int)   $hinvoice_id,
        'trader_invoice_no' => $inv['invoice_number'],
        'customer_name'     => trim($inv['provider_name']),
        'customer_pin'      => $hospital_kra_pin,
        'customer_mobile'   => $inv['hospital_phone']   ?? '',
        'customer_address'  => $inv['hospital_address'] ?? '',
        'amount_paid'       => (float) $inv['total_amount'],
        'change_given'      => 0.00,
        'payment_mode'      => $payment_mode,
        'items'             => $invoice_items,
        'remark'            => 'Hospital Services Invoice – ' . $inv['engagement_number'],
        'business_name'     => $business_name,
        'business_address'  => $business_address,
    ];

    hetims_log($log_dir, [
        'ts'            => date('Y-m-d\TH:i:sP'),
        'hinvoice_id'   => $hinvoice_id,
        'event'         => 'pre_submission',
        'customer_name' => $submit_data['customer_name'],
        'customer_pin'  => $submit_data['customer_pin'],
        'item_count'    => count($invoice_items),
        'total_amount'  => $submit_data['amount_paid'],
    ]);

    $response = $etims->submitInvoice($submit_data);

    hetims_log($log_dir, [
        'ts'          => date('Y-m-d\TH:i:sP'),
        'hinvoice_id' => $hinvoice_id,
        'event'       => 'api_response',
        'success'     => $response['success'],
        'result_cd'   => $response['result_cd'] ?? null,
        'message'     => $response['message']   ?? null,
    ]);

    // ── 6. Handle complete API / network failure ──────────────────────────────
    if (!$response['success']) {
        $fail_msg = $response['message'] ?? 'Unknown API error';
        hetims_mark_error($conn, $hinvoice_id, $fail_msg);
        throw new Exception("eTIMS API error: {$fail_msg}");
    }

    // ── 7. Parse response – three possible shapes ─────────────────────────────
    $resp_top   = $response['data']          ?? [];
    $inner_data = $resp_top['data']           ?? [];
    $kra_dto    = $inner_data['kraReceiptResponseDto'] ?? [];

    // Resolve KRA result code from whichever shape came back
    $result_cd  = $kra_dto['resultCd']   ?? $resp_top['resultCd']   ?? $response['result_cd'] ?? null;
    $result_msg = $kra_dto['resultMsg']  ?? $resp_top['resultMsg']  ?? 'OK';

    // Detect "already on KRA" response (invoice number exists but QR is present)
    $resp_msg_lc   = strtolower($response['message'] ?? '');
    $already_exists = (
        strpos($resp_msg_lc, 'invoice number exist') !== false
        && !empty($inner_data['invoiceNumberSdcIdUrl'])
    );

    // ── 7A: Invoice already on KRA – retrieve the QR and save ────────────────
    if ($already_exists) {
        $e_qr       = $inner_data['invoiceNumberSdcIdUrl'];
        $e_inv_no   = (string)($inner_data['invoiceNumber'] ?? '');
        $e_date     = date('Y-m-d H:i:s');
        $e_internal = null;
        $rcpt_sign  = null;

        hetims_log($log_dir, [
            'ts'          => date('Y-m-d\TH:i:sP'),
            'hinvoice_id' => $hinvoice_id,
            'note'        => 'Invoice already on KRA — saving QR from response',
            'qr'          => $e_qr,
        ]);

    // ── 7B: KRA logic rejection (result code not '000') ───────────────────────
    } elseif ($result_cd !== null && $result_cd !== '000') {
        $kra_errors = [
            '924' => 'Invoice number already exists on KRA (924).',
            '803' => 'Duplicate trader invoice number (803).',
            '902' => 'Invalid KRA PIN (902).',
            '910' => "Request parameter error — {$result_msg}",
        ];
        $err_msg = $kra_errors[$result_cd]
                ?? "KRA rejected invoice (code {$result_cd}): {$result_msg}";

        $fs = $conn->prepare(
            "UPDATE hospital_invoices
             SET etims_result_code    = ?,
                 etims_result_message = ?,
                 updated_at           = NOW()
             WHERE hinvoice_id = ?"
        );
        $fs->bind_param('ssi', $result_cd, $err_msg, $hinvoice_id);
        $fs->execute();
        $fs->close();
        $conn->commit();

        throw new Exception($err_msg);

    // ── 7C: Fresh success ─────────────────────────────────────────────────────
    } else {
        $rcpt_sign  = $resp_top['rcptSign']
                   ?? $inner_data['rcptSign']
                   ?? $kra_dto['data']['rcptSign']
                   ?? null;

        $intrl_data = $resp_top['intrlData'] ?? $inner_data['intrlData'] ?? null;
        $mrc_no     = $resp_top['mrcNo']     ?? $inner_data['mrcNo']     ?? null;
        $e_inv_no   = (string)($mrc_no ?: ($resp_top['totRcptNo'] ?? ''));

        // Parse KRA receipt date (format: YYYYMMDDHHmmss)
        $rcpt_dt = $resp_top['rcptPbctDt']
                ?? $resp_top['resultDt']
                ?? $kra_dto['resultDt']
                ?? null;

        $e_date = date('Y-m-d H:i:s');
        if ($rcpt_dt && preg_match(
            '/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/',
            $rcpt_dt, $m
        )) {
            $e_date = "{$m[1]}-{$m[2]}-{$m[3]} {$m[4]}:{$m[5]}:{$m[6]}";
        }

        // Internal data string: "cuSerial|rcptSign"
        $e_internal = trim(($intrl_data ?? '') . '|' . ($rcpt_sign ?? ''), '|') ?: null;

        // Extract QR – try all known shapes then build from rcptSign
        $e_qr = $etims->extractQrCode($resp_top);
        if (empty($e_qr) && !empty($inner_data['invoiceNumberSdcIdUrl'])) {
            $e_qr = $inner_data['invoiceNumberSdcIdUrl'];
        }

        if (empty($e_qr)) {
            hetims_log($log_dir, [
                'ts'          => date('Y-m-d\TH:i:sP'),
                'hinvoice_id' => $hinvoice_id,
                'warning'     => 'QR could not be built — rcptSign missing',
                'resp_keys'   => array_keys($resp_top),
            ]);
        }
    }

    // ── 8. Persist success to hospital_invoices ───────────────────────────────
    //       Advance DRAFT → SENT; leave PARTIAL_PAYMENT / PAID / OVERDUE intact.
    $e_qr_save       = $e_qr       ?? null;
    $e_inv_save      = $e_inv_no   ?? '';
    $e_internal_save = $e_internal ?? null;
    $rcpt_sign_save  = $rcpt_sign  ?? null;
    $e_date_save     = $e_date     ?? date('Y-m-d H:i:s');

    $upd = $conn->prepare(
        "UPDATE hospital_invoices
         SET etims_submitted       = 1,
             etims_invoice_number  = ?,
             etims_internal_data   = ?,
             etims_qr_code         = ?,
             etims_submission_date = ?,
             etims_result_code     = '000',
             etims_result_message  = 'Success',
             status = CASE
                          WHEN status = 'DRAFT' THEN 'SENT'
                          ELSE status
                      END,
             updated_at            = NOW()
         WHERE hinvoice_id = ?"
    );
    if (!$upd) {
        throw new Exception('DB prepare (update) failed: ' . $conn->error);
    }
    $upd->bind_param('ssssi',
        $e_inv_save,
        $e_internal_save,
        $e_qr_save,
        $e_date_save,
        $hinvoice_id
    );
    if (!$upd->execute()) {
        throw new Exception('DB update failed: ' . $conn->error);
    }
    $upd->close();

    // ── 9. Activity log  (logged_at — NOT created_at per schema) ─────────────
    $uid = (int)$_SESSION['user_id'];
    $act = 'ETIMS_SUBMIT_HINVOICE';
    $mod = 'HOSPITAL_BILLING';
    $rt  = 'hospital_invoices';

    $log_stmt = $conn->prepare(
        "INSERT INTO activity_log
             (user_id, action, module, record_id, record_type, logged_at)
         VALUES (?, ?, ?, ?, ?, NOW())"
    );
    if ($log_stmt) {
        $log_stmt->bind_param('issis', $uid, $act, $mod, $hinvoice_id, $rt);
        $log_stmt->execute();
        $log_stmt->close();
    }

    $conn->commit();

    // ── 10. Return success ────────────────────────────────────────────────────
    echo json_encode([
        'success' => true,
        'message' => $already_exists
            ? 'Invoice was already on KRA — QR code retrieved and saved.'
            : 'Hospital invoice submitted to eTIMS successfully.',
        'data' => [
            'hinvoice_id'       => $hinvoice_id,
            'cu_invoice_number' => $e_inv_save,
            'receipt_date'      => $e_date_save,
            'receipt_signature' => $rcpt_sign_save,
            'internal_data'     => $e_internal_save,
            'qr_code'           => $e_qr_save,
            'customer_name'     => $submit_data['customer_name'],
            'customer_pin'      => $submit_data['customer_pin'],
            'result_code'       => $result_cd,
            'already_existed'   => $already_exists,
        ],
    ]);

} catch (Exception $e) {
    $conn->rollback();

    hetims_log($log_dir, [
        'ts'          => date('Y-m-d\TH:i:sP'),
        'hinvoice_id' => $hinvoice_id,
        'event'       => 'error',
        'error'       => $e->getMessage(),
    ]);

    $out = ['success' => false, 'message' => $e->getMessage()];
    if ($response !== null) {
        $out['api_response'] = $response;
    }
    echo json_encode($out);
}