<?php
error_reporting(E_ALL);
ini_set('display_errors', 0);
header('Content-Type: application/json; charset=UTF-8');
ob_start();

require_once __DIR__ . '/config/koneksi.php';
require_once __DIR__ . '/config/jwt.php';

function json_out($success, $message, $extra = [], $code = 200) {
    while (ob_get_level() > 0) ob_end_clean();
    http_response_code($code);
    echo json_encode(array_merge([
        'success' => (bool)$success,
        'message' => $message,
    ], $extra), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

set_exception_handler(function ($e) {
    json_out(false, 'Server sync_full error: ' . $e->getMessage(), [], 500);
});

register_shutdown_function(function () {
    $e = error_get_last();
    if ($e && in_array($e['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) {
        json_out(false, 'Fatal error sync_full: ' . $e['message'], [], 500);
    }
});

function db_conn() {
    global $conn, $koneksi;
    if (isset($conn) && $conn instanceof mysqli) return $conn;
    if (isset($koneksi) && $koneksi instanceof mysqli) return $koneksi;
    json_out(false, 'Koneksi database tidak tersedia', [], 500);
}

function input_json() {
    $raw = file_get_contents('php://input');
    $data = json_decode($raw, true);
    if (!is_array($data)) json_out(false, 'Request JSON tidak valid', [], 400);
    return $data;
}

function clean_name($name) {
    $name = trim((string)$name);
    if (!preg_match('/^[a-zA-Z0-9_]+$/', $name)) {
        json_out(false, 'Nama tabel/kolom tidak valid', [], 400);
    }
    return $name;
}

function allowed_tables() {
    return [
        'app_users',
        'tb_supplier',
        'tb_pelanggan',
        'tb_kategori',
        'tb_satuan',
        'tb_bank',
        'tb_metode_bayar',
        'tb_kategori_pengeluaran',
        'tb_barang',
        'tb_pembelian',
        'tb_pembelian_detail',
        'tb_pembayaran_supplier',
        'tb_pengeluaran',
        'tb_penjualan',
        'tb_penjualan_detail',
        'tb_pembayaran_pelanggan',
        'tb_retur_penjualan',
        'tb_invoice',
        'tb_pembayaran_invoice',
        'tb_kartu_stok',
        'tb_closing_bulanan',
    ];
}

function table_exists(mysqli $db, $table) {
    $table = $db->real_escape_string($table);
    $res = $db->query("SHOW TABLES LIKE '{$table}'");
    return $res instanceof mysqli_result && $res->num_rows > 0;
}

function column_exists(mysqli $db, $table, $column) {
    $table = clean_name($table);
    $column = $db->real_escape_string($column);
    $res = $db->query("SHOW COLUMNS FROM `{$table}` LIKE '{$column}'");
    return $res instanceof mysqli_result && $res->num_rows > 0;
}

function fetch_all_assoc_no_mysqlnd(mysqli_stmt $stmt) {
    $stmt->execute();
    $meta = $stmt->result_metadata();
    if (!$meta) return [];

    $row = [];
    $bind = [];
    $fields = $meta->fetch_fields();

    foreach ($fields as $field) {
        $row[$field->name] = null;
        $bind[] = &$row[$field->name];
    }

    call_user_func_array([$stmt, 'bind_result'], $bind);

    $rows = [];
    while ($stmt->fetch()) {
        $item = [];
        foreach ($row as $key => $value) {
            $item[$key] = $value;
        }
        unset($item['id']);
        $rows[] = $item;
    }

    return $rows;
}

$db = db_conn();
$input = input_json();

$companyId = trim((string)($input['company_id'] ?? ''));
$since = trim((string)($input['since'] ?? ''));
$requestedTables = $input['tables'] ?? null;

if ($companyId === '') {
    json_out(false, 'company_id wajib', [], 400);
}

$tables = allowed_tables();

if (is_array($requestedTables) && !empty($requestedTables)) {
    $filtered = [];
    foreach ($requestedTables as $t) {
        $t = clean_name($t);
        if (in_array($t, $tables, true)) $filtered[] = $t;
    }
    $tables = $filtered;
}

$data = [];
$totalRows = 0;

foreach ($tables as $table) {
    if (!table_exists($db, $table)) {
        $data[$table] = [];
        continue;
    }

    if (!column_exists($db, $table, 'company_id') || !column_exists($db, $table, 'uuid')) {
        $data[$table] = [];
        continue;
    }

    $hasUpdatedAt = column_exists($db, $table, 'updated_at');

    if ($since !== '' && $hasUpdatedAt) {
        $sql = "SELECT * FROM `{$table}` WHERE company_id = ? AND updated_at > ? ORDER BY updated_at ASC";
        $stmt = $db->prepare($sql);
        if (!$stmt) throw new Exception('Prepare pull gagal ' . $table . ': ' . $db->error);
        $stmt->bind_param('ss', $companyId, $since);
    } else {
        $sql = "SELECT * FROM `{$table}` WHERE company_id = ? ORDER BY uuid ASC";
        $stmt = $db->prepare($sql);
        if (!$stmt) throw new Exception('Prepare full gagal ' . $table . ': ' . $db->error);
        $stmt->bind_param('s', $companyId);
    }

    $rows = fetch_all_assoc_no_mysqlnd($stmt);
    $stmt->close();

    $data[$table] = $rows;
    $totalRows += count($rows);
}

json_out(true, 'Sync full berhasil', [
    'data' => $data,
    'server_time' => date('Y-m-d H:i:s'),
    'total_rows' => $totalRows,
]);