<?php
// MJ Marketplace v2.9.17 - Pending update review helpers for listings, companies and deals.
// Rule: active/live public records are not overwritten by user edits until admin approves.

if (!function_exists('mj_review_ensure_schema')) {
function mj_review_ensure_schema(): void {
    if (!function_exists('q') || !mj_is_installed()) { return; }
    try {
        if (table_exists('mj_listing_revisions')) {
            foreach ([
                'old_images_json' => 'LONGTEXT NULL AFTER new_data_json',
                'new_images_json' => 'LONGTEXT NULL AFTER old_images_json',
                'deleted_images_json' => 'LONGTEXT NULL AFTER new_images_json'
            ] as $col=>$def) { if (!mj_column_exists('mj_listing_revisions', $col)) { try { q('ALTER TABLE mj_listing_revisions ADD COLUMN `'.$col.'` '.$def); } catch(Throwable $e) {} } }
        }
    } catch(Throwable $e) {}
    try {
        q("CREATE TABLE IF NOT EXISTS mj_company_revisions (
            id BIGINT AUTO_INCREMENT PRIMARY KEY,
            company_id BIGINT NOT NULL,
            user_id BIGINT NULL,
            old_data_json LONGTEXT NULL,
            new_data_json LONGTEXT NULL,
            old_extra_json LONGTEXT NULL,
            new_extra_json LONGTEXT NULL,
            status VARCHAR(40) NOT NULL DEFAULT 'pending',
            admin_id BIGINT NULL,
            admin_note TEXT NULL,
            reject_reason TEXT NULL,
            submitted_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            reviewed_at DATETIME NULL,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            INDEX idx_company_status(company_id,status),
            INDEX idx_user_status(user_id,status),
            INDEX idx_submitted(submitted_at)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    } catch(Throwable $e) {}
    try {
        q("CREATE TABLE IF NOT EXISTS mj_deal_revisions (
            id BIGINT AUTO_INCREMENT PRIMARY KEY,
            deal_id BIGINT NOT NULL,
            user_id BIGINT NULL,
            old_data_json LONGTEXT NULL,
            new_data_json LONGTEXT NULL,
            old_extra_json LONGTEXT NULL,
            new_extra_json LONGTEXT NULL,
            status VARCHAR(40) NOT NULL DEFAULT 'pending',
            admin_id BIGINT NULL,
            admin_note TEXT NULL,
            reject_reason TEXT NULL,
            submitted_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            reviewed_at DATETIME NULL,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            INDEX idx_deal_status(deal_id,status),
            INDEX idx_user_status(user_id,status),
            INDEX idx_submitted(submitted_at)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    } catch(Throwable $e) {}
}
}

if (!function_exists('mj_review_is_live_status')) {
function mj_review_is_live_status(string $status): bool {
    $s = strtolower(trim($status));
    return in_array($s, ['active','approved','published','live','visible'], true);
}
}

if (!function_exists('mj_review_live_update_required')) {
function mj_review_live_update_required(string $type, string $status): bool {
    $type = strtolower(preg_replace('/[^a-z_]/', '', $type));
    if (!mj_review_is_live_status($status)) { return false; }
    $key = $type . '_update_review_required';
    return setting($key, '1') !== '0';
}
}

if (!function_exists('mj_review_table')) {
function mj_review_table(string $type): ?array {
    $type = strtolower($type);
    if ($type === 'listing') return ['table'=>'mj_listing_revisions','id_col'=>'listing_id','label'=>'Listing','admin_url'=>'listing-revisions.php','user_url'=>'my-listings.php'];
    if ($type === 'company') return ['table'=>'mj_company_revisions','id_col'=>'company_id','label'=>'Company','admin_url'=>'company-revisions.php','user_url'=>'my-companies.php'];
    if ($type === 'deal') return ['table'=>'mj_deal_revisions','id_col'=>'deal_id','label'=>'Deal','admin_url'=>'deal-revisions.php','user_url'=>'my-deals.php'];
    return null;
}
}

if (!function_exists('mj_review_pending')) {
function mj_review_pending(string $type, int $entityId): ?array {
    mj_review_ensure_schema();
    $cfg = mj_review_table($type);
    if (!$cfg || !table_exists($cfg['table'])) { return null; }
    try { return one('SELECT * FROM `'.$cfg['table'].'` WHERE `'.$cfg['id_col'].'`=? AND status="pending" ORDER BY id DESC LIMIT 1', [$entityId]) ?: null; }
    catch(Throwable $e) { return null; }
}
}

if (!function_exists('mj_review_pending_count')) {
function mj_review_pending_count(string $type): int {
    mj_review_ensure_schema();
    $cfg = mj_review_table($type);
    if (!$cfg || !table_exists($cfg['table'])) { return 0; }
    try { return safe_count('SELECT COUNT(*) c FROM `'.$cfg['table'].'` WHERE status="pending"'); }
    catch(Throwable $e) { return 0; }
}
}

if (!function_exists('mj_review_json')) {
function mj_review_json($data): string {
    if (function_exists('mj_safe_json')) { return mj_safe_json($data); }
    return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}
}

if (!function_exists('mj_review_submit')) {
function mj_review_submit(string $type, int $entityId, ?int $userId, array $oldData, array $newData, array $oldExtra = [], array $newExtra = []): int {
    mj_review_ensure_schema();
    $cfg = mj_review_table($type);
    if (!$cfg || !table_exists($cfg['table'])) { throw new RuntimeException('Update review table is not ready. Please run latest migration.'); }
    $pending = mj_review_pending($type, $entityId);
    $oldJson = mj_review_json($oldData);
    $newJson = mj_review_json($newData);
    $oldExtraJson = mj_review_json($oldExtra);
    $newExtraJson = mj_review_json($newExtra);
    if ($pending) {
        q('UPDATE `'.$cfg['table'].'` SET old_data_json=?, new_data_json=?, old_extra_json=?, new_extra_json=?, user_id=?, submitted_at=NOW(), status="pending", admin_id=NULL, admin_note=NULL, reject_reason=NULL, reviewed_at=NULL WHERE id=?', [$oldJson,$newJson,$oldExtraJson,$newExtraJson,$userId,(int)$pending['id']]);
        return (int)$pending['id'];
    }
    q('INSERT INTO `'.$cfg['table'].'` (`'.$cfg['id_col'].'`,user_id,old_data_json,new_data_json,old_extra_json,new_extra_json,status,submitted_at,created_at) VALUES(?,?,?,?,?,? ,"pending",NOW(),NOW())', [$entityId,$userId,$oldJson,$newJson,$oldExtraJson,$newExtraJson]);
    return (int)db()->lastInsertId();
}
}

if (!function_exists('mj_review_admin_alert')) {
function mj_review_admin_alert(string $type, int $entityId, string $title): void {
    $cfg = mj_review_table($type); if (!$cfg) return;
    $label = $cfg['label'];
    try { mj263_notify(null, 1, $type.'_revision', $label.' update pending review', $title, 'admin/'.$cfg['admin_url'], 'high'); } catch(Throwable $e) {}
    try { mj_create_admin_alert([
        'alert_key'=>$type.'_revision_'.$entityId.'_'.date('YmdHi'),
        'alert_type'=>$type.'_revision',
        'module_name'=>$type.'s',
        'priority'=>'high',
        'title'=>$label.' update pending review',
        'message'=>$title,
        'action_url'=>$cfg['admin_url'],
        'action_label'=>'Review',
        'related_type'=>$type,
        'related_id'=>$entityId
    ]); } catch(Throwable $e) {}
}
}

if (!function_exists('mj_review_short')) {
function mj_review_short($value, int $len=180): string {
    $txt = trim(strip_tags((string)$value));
    if (function_exists('mb_strimwidth')) return mb_strimwidth($txt, 0, $len, '...');
    return strlen($txt) > $len ? substr($txt, 0, $len-3).'...' : $txt;
}
}

if (!function_exists('mj_review_diff_keys')) {
function mj_review_diff_keys(array $old, array $new, array $keys): array {
    $out = [];
    foreach ($keys as $k) { if ((string)($old[$k] ?? '') !== (string)($new[$k] ?? '')) { $out[] = $k; } }
    return $out;
}
}

if (!function_exists('mj_review_apply_company')) {
function mj_review_apply_company(array $rev, int $adminId, string $adminNote=''): void {
    $companyId = (int)($rev['company_id'] ?? 0);
    $new = json_decode((string)($rev['new_data_json'] ?? '{}'), true) ?: [];
    $extra = json_decode((string)($rev['new_extra_json'] ?? '{}'), true) ?: [];
    if ($companyId <= 0 || !$new) { throw new RuntimeException('Invalid company revision.'); }
    $live = one('SELECT * FROM mj_companies WHERE id=? LIMIT 1', [$companyId]);
    if (!$live) { throw new RuntimeException('Company not found.'); }
    $new['status'] = mj_review_is_live_status((string)($live['status'] ?? '')) ? (string)($live['status'] ?? 'active') : 'active';
    $new['rejection_reason'] = null;
    $new['last_reviewed_at'] = date('Y-m-d H:i:s');
    $new['last_reviewed_by'] = $adminId;
    $new = mj_company_filter_columns_fresh('mj_companies', $new);
    $sets=[]; $params=[];
    foreach ($new as $k=>$v) { $sets[]='`'.$k.'`=?'; $params[]=$v; }
    if ($sets) { $params[]=$companyId; q('UPDATE mj_companies SET '.implode(',', $sets).', updated_at=NOW() WHERE id=?', $params); }
    if (!empty($extra['branch_data']) && is_array($extra['branch_data']) && function_exists('mj_company_update_main_branch')) { mj_company_update_main_branch($companyId, array_merge($new, $extra['branch_data'])); }
    if (array_key_exists('services_text', $extra) && function_exists('mj_company_save_services_from_text')) { mj_company_save_services_from_text($companyId, (string)$extra['services_text']); }
    if (function_exists('mj_company_update_scores')) { mj_company_update_scores($companyId); }
    if (function_exists('mj_company_timeline_add')) { mj_company_timeline_add($companyId, 'admin', $adminId, 'revision_approved', 'Company update approved. '.$adminNote, (string)($live['status'] ?? ''), (string)($new['status'] ?? 'active')); }
    q('UPDATE mj_company_revisions SET status="approved", admin_id=?, admin_note=?, reviewed_at=NOW() WHERE id=?', [$adminId,$adminNote,(int)$rev['id']]);
    if (!empty($rev['user_id'])) { mj263_notify((int)$rev['user_id'], null, 'company_revision_approved', 'Company update approved', 'Your company profile update has been approved.', 'my-companies.php', 'normal', true); }
    admin_log('company_revision_approved','mj_company_revisions',(int)$rev['id'],['company_id'=>$companyId]);
}
}

if (!function_exists('mj_review_apply_deal')) {
function mj_review_apply_deal(array $rev, int $adminId, string $adminNote=''): void {
    $dealId = (int)($rev['deal_id'] ?? 0);
    $new = json_decode((string)($rev['new_data_json'] ?? '{}'), true) ?: [];
    if ($dealId <= 0 || !$new) { throw new RuntimeException('Invalid deal revision.'); }
    $live = one('SELECT * FROM mj_deals WHERE id=? LIMIT 1', [$dealId]);
    if (!$live) { throw new RuntimeException('Deal not found.'); }
    $new['status'] = mj_review_is_live_status((string)($live['status'] ?? '')) ? (string)($live['status'] ?? 'active') : 'active';
    $new['reject_reason'] = null;
    $new['approved_by'] = $adminId;
    $new['approved_at'] = date('Y-m-d H:i:s');
    $new = mj_deal_filter_existing_columns($new);
    $sets=[]; $params=[];
    foreach ($new as $k=>$v) { $sets[]='`'.$k.'`=?'; $params[]=$v; }
    if ($sets) { $params[]=$dealId; q('UPDATE mj_deals SET '.implode(',', $sets).', updated_at=NOW() WHERE id=?', $params); }
    q('UPDATE mj_deal_revisions SET status="approved", admin_id=?, admin_note=?, reviewed_at=NOW() WHERE id=?', [$adminId,$adminNote,(int)$rev['id']]);
    if (!empty($rev['user_id'])) { mj263_notify((int)$rev['user_id'], null, 'deal_revision_approved', 'Deal update approved', 'Your deal update has been approved.', 'my-deals.php', 'normal', true); }
    admin_log('deal_revision_approved','mj_deal_revisions',(int)$rev['id'],['deal_id'=>$dealId]);
}
}
?>
