<?php
// MJ Marketplace v3.0.0 helpers - global notifications, deal limits/upgrades, lightweight charts.
// Locked payment scope: customers cannot pay sellers/users through MJ Marketplace.

if (!function_exists('mj_v300_add_column')) {
function mj_v300_add_column(string $table, string $column, string $sql): void {
    try { if (mj_is_installed() && table_exists($table) && !mj_column_exists($table, $column)) { q($sql); } } catch (Throwable $e) {}
}
}

if (!function_exists('mj_v300_ensure_schema')) {
function mj_v300_ensure_schema(): void {
    static $done = false;
    if ($done) { return; }
    if (!mj_is_installed()) { return; }
    $done = true;
    try { mj263_schema(); } catch (Throwable $e) {}
    try { mj_user_limits_ensure_schema(); } catch (Throwable $e) {}
    try { mj_deal_ensure_schema(); } catch (Throwable $e) {}
    try { mj2919_cart_ensure_schema(); } catch (Throwable $e) {}
    mj_v300_add_column('mj_user_limits','max_deals','ALTER TABLE mj_user_limits ADD COLUMN max_deals INT NULL AFTER max_companies');
    mj_v300_add_column('mj_user_limits','deal_auto_approve','ALTER TABLE mj_user_limits ADD COLUMN deal_auto_approve TINYINT(1) NULL AFTER max_deals');
    mj_v300_add_column('mj_user_limits','allow_sponsored_deal','ALTER TABLE mj_user_limits ADD COLUMN allow_sponsored_deal TINYINT(1) NULL AFTER deal_auto_approve');
    mj_v300_add_column('mj_user_limits','allow_featured_deal','ALTER TABLE mj_user_limits ADD COLUMN allow_featured_deal TINYINT(1) NULL AFTER allow_sponsored_deal');
    mj_v300_add_column('mj_deals','sponsored_until','ALTER TABLE mj_deals ADD COLUMN sponsored_until DATETIME NULL AFTER is_sponsored');
    mj_v300_add_column('mj_deals','is_urgent','ALTER TABLE mj_deals ADD COLUMN is_urgent TINYINT(1) NOT NULL DEFAULT 0 AFTER sponsored_until');
    mj_v300_add_column('mj_deals','urgent_until','ALTER TABLE mj_deals ADD COLUMN urgent_until DATETIME NULL AFTER is_urgent');
    mj_v300_add_column('mj_deals','is_bumped','ALTER TABLE mj_deals ADD COLUMN is_bumped TINYINT(1) NOT NULL DEFAULT 0 AFTER urgent_until');
    mj_v300_add_column('mj_deals','bumped_until','ALTER TABLE mj_deals ADD COLUMN bumped_until DATETIME NULL AFTER is_bumped');
    mj_v300_add_column('mj_deals','is_homepage','ALTER TABLE mj_deals ADD COLUMN is_homepage TINYINT(1) NOT NULL DEFAULT 0 AFTER bumped_until');
    mj_v300_add_column('mj_deals','homepage_until','ALTER TABLE mj_deals ADD COLUMN homepage_until DATETIME NULL AFTER is_homepage');
    mj_v300_add_column('mj_deals','renewed_until','ALTER TABLE mj_deals ADD COLUMN renewed_until DATETIME NULL AFTER homepage_until');
    try { q("CREATE TABLE IF NOT EXISTS mj_browser_push_subscriptions (id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NULL, admin_id BIGINT NULL, customer_token VARCHAR(191) NULL, endpoint TEXT NULL, auth_key VARCHAR(255) NULL, p256dh_key VARCHAR(255) NULL, permission_status VARCHAR(40) NULL, user_agent TEXT NULL, last_seen_at DATETIME NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX(user_id), INDEX(admin_id), INDEX(customer_token)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch (Throwable $e) {}
    $settings = [
        'mj_v3_enabled'=>'1','customer_to_user_payments_disabled'=>'1','marketplace_payment_scope_locked'=>'1','global_notifications_enabled'=>'1','global_notification_poll_seconds'=>'25','browser_notifications_enabled'=>'1','notification_popup_position'=>'bottom-right','notification_sound_enabled'=>'0','default_max_deals_per_user'=>'3','extra_deal_slot_charge_amount'=>'5.00','deal_renewal_charge_amount'=>'5.00','deal_renewal_default_days'=>'30','deal_featured_charge_amount'=>setting('deal_featured_charge_amount','10.00'),'deal_sponsored_charge_amount'=>setting('deal_sponsored_charge_amount','15.00'),'deal_homepage_charge_amount'=>'25.00','deal_bump_charge_amount'=>'3.00','deal_urgent_charge_amount'=>'3.00','deal_upgrade_default_days'=>'7','deal_upgrade_max_days'=>'90','deal_auto_approve'=>'0','seller_dashboard_charts_enabled'=>'1','admin_dashboard_charts_enabled'=>'1'
    ];
    foreach ($settings as $k=>$v) { try { q('INSERT INTO mj_settings(setting_key,setting_value) VALUES(?,?) ON DUPLICATE KEY UPDATE setting_value=setting_value', [$k,(string)$v]); } catch (Throwable $e) {} }
}
}

if (!function_exists('mj_v300_user_limits')) {
function mj_v300_user_limits(int $userId): array {
    mj_v300_ensure_schema();
    $base = function_exists('mj_user_limits_get') ? mj_user_limits_get($userId) : ['max_listings'=>5,'max_companies'=>1];
    $row = null;
    try { $row = table_exists('mj_user_limits') ? one('SELECT * FROM mj_user_limits WHERE user_id=? LIMIT 1', [$userId]) : null; } catch (Throwable $e) {}
    $base['max_deals'] = isset($row['max_deals']) && $row['max_deals'] !== null && $row['max_deals'] !== '' ? (int)$row['max_deals'] : max(0,(int)setting('default_max_deals_per_user','3'));
    $base['deal_auto_approve'] = isset($row['deal_auto_approve']) && $row['deal_auto_approve'] !== null ? (int)$row['deal_auto_approve'] : (setting('deal_auto_approve','0')==='1'?1:0);
    $base['allow_sponsored_deal'] = isset($row['allow_sponsored_deal']) && $row['allow_sponsored_deal'] !== null ? (int)$row['allow_sponsored_deal'] : 1;
    $base['allow_featured_deal'] = isset($row['allow_featured_deal']) && $row['allow_featured_deal'] !== null ? (int)$row['allow_featured_deal'] : 1;
    return $base;
}
}
if (!function_exists('mj_v300_user_deal_count')) {
function mj_v300_user_deal_count(int $userId): int { try { return table_exists('mj_deals') ? safe_count('SELECT COUNT(*) c FROM mj_deals WHERE user_id=? AND status NOT IN ("deleted","rejected")', [$userId]) : 0; } catch (Throwable $e) { return 0; } }
}
if (!function_exists('mj_v300_deal_limit_status')) {
function mj_v300_deal_limit_status(int $userId): array { $limits=mj_v300_user_limits($userId); $used=mj_v300_user_deal_count($userId); $max=max(0,(int)($limits['max_deals']??0)); return ['used'=>$used,'max'=>$max,'remaining'=>max(0,$max-$used),'allowed'=>$max<=0||$used<$max,'limits'=>$limits]; }
}
if (!function_exists('mj_v300_assert_can_create_deal')) {
function mj_v300_assert_can_create_deal(int $userId): void { $s=mj_v300_deal_limit_status($userId); if(!$s['allowed']) throw new RuntimeException('You have reached your deal limit ('.$s['used'].'/'.$s['max'].'). Please buy extra deal slots from Billing & Payments > Cart.'); }
}
if (!function_exists('mj_v300_deal_upgrade_options')) {
function mj_v300_deal_upgrade_options(): array { return [
 'deal_featured'=>['label'=>'Featured Deal','setting'=>'deal_featured_charge_amount','default'=>'10.00','days'=>true,'desc'=>'Show in featured deal sections.'],
 'deal_sponsored'=>['label'=>'Sponsored Deal','setting'=>'deal_sponsored_charge_amount','default'=>'15.00','days'=>true,'desc'=>'Priority sponsored placement in deal search/category/city.'],
 'deal_homepage'=>['label'=>'Homepage Deal','setting'=>'deal_homepage_charge_amount','default'=>'25.00','days'=>true,'desc'=>'Show in homepage deal spotlight.'],
 'deal_bump'=>['label'=>'Bump Deal','setting'=>'deal_bump_charge_amount','default'=>'3.00','days'=>true,'desc'=>'Push deal higher for selected days.'],
 'deal_urgent'=>['label'=>'Urgent Deal Label','setting'=>'deal_urgent_charge_amount','default'=>'3.00','days'=>true,'desc'=>'Add urgent/hot badge for selected days.'],
 'deal_renewal'=>['label'=>'Renew Deal','setting'=>'deal_renewal_charge_amount','default'=>'5.00','days'=>true,'desc'=>'Extend deal expiry.'],
 'extra_deal_slot'=>['label'=>'Extra Deal Slots','setting'=>'extra_deal_slot_charge_amount','default'=>'5.00','days'=>false,'desc'=>'Increase deal posting limit.']
]; }
}
if (!function_exists('mj_v300_activate_deal_item')) {
function mj_v300_activate_deal_item(string $type, int $userId, int $targetId, int $qty, int $adminId=0, string $note=''): string {
    mj_v300_ensure_schema(); $qty=max(1,$qty);
    if($type==='extra_deal_slot') { $limits=mj_v300_user_limits($userId); $newMax=max(0,(int)$limits['max_deals'])+$qty; q('INSERT INTO mj_user_limits(user_id,max_listings,max_companies,max_deals,note,updated_by,updated_at) VALUES(?,?,?,?,?,?,NOW()) ON DUPLICATE KEY UPDATE max_deals=VALUES(max_deals), note=VALUES(note), updated_by=VALUES(updated_by), updated_at=NOW()',[$userId,(int)($limits['max_listings']??0),(int)($limits['max_companies']??0),$newMax,'Extra deal slots approved from payment.',$adminId]); if(function_exists('mj263_notify')) mj263_notify($userId,null,'extra_deal_slots_approved','Extra deal slots approved','Your deal limit increased by '.$qty.'. New deal limit: '.$newMax.'.','my-deals.php','normal',true); return 'Added '.$qty.' extra deal slot(s). New deal limit: '.$newMax.'.'; }
    if(!table_exists('mj_deals') || $targetId<=0) return 'Deal target not found.'; $deal=one('SELECT * FROM mj_deals WHERE id=? AND user_id=? LIMIT 1',[$targetId,$userId]); if(!$deal) return 'Deal target not found.';
    $days=$qty; $until=date('Y-m-d H:i:s', strtotime('+'.$days.' days')); $title=(string)($deal['title']??('Deal #'.$targetId));
    if($type==='deal_renewal') { $base=time(); if(!empty($deal['end_at']) && strtotime((string)$deal['end_at'])>time()) $base=strtotime((string)$deal['end_at']); $newEnd=date('Y-m-d H:i:s', strtotime('+'.$days.' days',$base)); q('UPDATE mj_deals SET end_at=?, renewed_until=?, status=IF(status IN ("expired","draft","pending","rejected"),"active",status), updated_at=NOW() WHERE id=? AND user_id=?',[$newEnd,$newEnd,$targetId,$userId]); if(function_exists('mj263_notify')) mj263_notify($userId,null,'deal_renewed','Deal renewed','Your deal "'.$title.'" was renewed until '.$newEnd.'.','my-deals.php','normal',true); return 'Renewed deal #'.$targetId.' until '.$newEnd.'.'; }
    $map=['deal_featured'=>['is_featured','featured_until','Featured deal activated'],'deal_sponsored'=>['is_sponsored','sponsored_until','Sponsored deal activated'],'deal_homepage'=>['is_homepage','homepage_until','Homepage deal activated'],'deal_bump'=>['is_bumped','bumped_until','Deal bump activated'],'deal_urgent'=>['is_urgent','urgent_until','Urgent deal label activated']];
    if(isset($map[$type])) { [$flag,$col,$label]=$map[$type]; q('UPDATE mj_deals SET `'.$flag.'`=1, `'.$col.'`=?, status=IF(status IN ("draft","pending","rejected","expired"),"active",status), updated_at=NOW() WHERE id=? AND user_id=?',[$until,$targetId,$userId]); if(function_exists('mj263_notify')) mj263_notify($userId,null,$type.'_approved',$label,'Your deal "'.$title.'" promotion is active until '.$until.'.','my-deals.php','normal',true); return $label.' until '.$until.'.'; }
    return 'No deal activation rule for '.$type.'.';
}
}
if (!function_exists('mj_v300_chart_data_attr')) { function mj_v300_chart_data_attr(array $data): string { return e(json_encode($data, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE)); } }
if (!function_exists('mj_v300_admin_chart_data')) {
function mj_v300_admin_chart_data(): array {
    $pending=[['label'=>'Payments','value'=>table_exists('mj_payment_batches')?safe_count('SELECT COUNT(*) c FROM mj_payment_batches WHERE status IN ("pending_review","payment_uploaded")'):0],['label'=>'Listing updates','value'=>table_exists('mj_listing_revisions')?safe_count('SELECT COUNT(*) c FROM mj_listing_revisions WHERE status="pending"'):0],['label'=>'Company updates','value'=>table_exists('mj_company_revisions')?safe_count('SELECT COUNT(*) c FROM mj_company_revisions WHERE status="pending"'):0],['label'=>'Deal updates','value'=>table_exists('mj_deal_revisions')?safe_count('SELECT COUNT(*) c FROM mj_deal_revisions WHERE status="pending"'):0],['label'=>'Failed email','value'=>table_exists('mj_email_queue')?safe_count('SELECT COUNT(*) c FROM mj_email_queue WHERE status="failed"'):0]];
    $dealStatus=[['label'=>'Active','value'=>table_exists('mj_deals')?safe_count('SELECT COUNT(*) c FROM mj_deals WHERE status IN ("active","approved")'):0],['label'=>'Pending','value'=>table_exists('mj_deals')?safe_count('SELECT COUNT(*) c FROM mj_deals WHERE status IN ("pending","pending_review")'):0],['label'=>'Expired','value'=>table_exists('mj_deals')?safe_count('SELECT COUNT(*) c FROM mj_deals WHERE status="expired" OR (end_at IS NOT NULL AND end_at<NOW())'):0],['label'=>'Featured','value'=>table_exists('mj_deals')?safe_count('SELECT COUNT(*) c FROM mj_deals WHERE is_featured=1 AND (featured_until IS NULL OR featured_until>=NOW())'):0],['label'=>'Sponsored','value'=>table_exists('mj_deals')?safe_count('SELECT COUNT(*) c FROM mj_deals WHERE is_sponsored=1 AND (sponsored_until IS NULL OR sponsored_until>=NOW())'):0]];
    $revenue=[]; try{ if(table_exists('mj_receipts')){ foreach(all_rows('SELECT DATE_FORMAT(created_at,"%b") m, COALESCE(SUM(amount),0) amt FROM mj_receipts WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL 5 MONTH) GROUP BY DATE_FORMAT(created_at,"%Y-%m"), DATE_FORMAT(created_at,"%b") ORDER BY MIN(created_at)') as $r){ $revenue[]=['label'=>(string)$r['m'],'value'=>(float)$r['amt']]; } } }catch(Throwable $e){}
    return ['pending'=>$pending,'dealStatus'=>$dealStatus,'revenue'=>$revenue];
}
}
if (!function_exists('mj_v300_user_performance_data')) {
function mj_v300_user_performance_data(int $userId): array { $out=[]; try{ $out[]=['label'=>'Listing views','value'=>table_exists('mj_listings')?(int)(one('SELECT COALESCE(SUM(views),0) v FROM mj_listings WHERE user_id=?',[$userId])['v']??0):0]; $out[]=['label'=>'Deal views','value'=>table_exists('mj_deals')?(int)(one('SELECT COALESCE(SUM(view_count),0) v FROM mj_deals WHERE user_id=?',[$userId])['v']??0):0]; $out[]=['label'=>'Deal enquiries','value'=>table_exists('mj_deal_enquiries')?safe_count('SELECT COUNT(*) c FROM mj_deal_enquiries WHERE seller_user_id=? OR user_id=?',[$userId,$userId]):0]; $out[]=['label'=>'WhatsApp clicks','value'=>table_exists('mj_deals')?(int)(one('SELECT COALESCE(SUM(whatsapp_click_count),0) v FROM mj_deals WHERE user_id=?',[$userId])['v']??0):0]; $out[]=['label'=>'Call clicks','value'=>table_exists('mj_deals')?(int)(one('SELECT COALESCE(SUM(call_click_count),0) v FROM mj_deals WHERE user_id=?',[$userId])['v']??0):0]; }catch(Throwable $e){} return $out; }
}
if (!function_exists('mj_v300_render_limit_card')) {
function mj_v300_render_limit_card(string $label, int $used, int $max, string $url, string $icon='bi-bar-chart'): void { $pct=$max>0?min(100,round(($used/$max)*100)):0; echo '<div class="mj-v3-limit-card"><div><i class="bi '.e($icon).'"></i><b>'.e($label).'</b><span>'.e($used).' / '.e($max).' used</span></div><div class="mj-v3-progress"><em style="width:'.$pct.'%"></em></div><a href="'.e($url).'">Manage</a></div>'; }
}
?>
