<?php
/**
 * MJ Marketplace v2.8.8 helpers.
 * Safe helpers for country themes, company page builder, bookings, dashboards,
 * timeline, link/system health, status badges and missing-table fallbacks.
 */
if (!defined('MJ_V288_HELPERS_LOADED')) { define('MJ_V288_HELPERS_LOADED', true); }

if (!function_exists('mj_v288_clean_key')) {
function mj_v288_clean_key(string $value): string { return preg_replace('/[^a-zA-Z0-9_\-]/', '', $value) ?: ''; }
}

if (!function_exists('mj_v288_country_theme_defaults')) {
function mj_v288_country_theme_defaults(?string $iso2 = null): array {
    $iso2 = strtoupper((string)$iso2);
    $map = [
        'SG' => ['primary'=>'#ef3340','secondary'=>'#ffffff','accent'=>'#b91c1c','text'=>'#111827','gradient'=>'linear-gradient(135deg,#ef3340 0%,#ffffff 100%)'],
        'MY' => ['primary'=>'#0033a0','secondary'=>'#ffcc00','accent'=>'#cc0001','text'=>'#111827','gradient'=>'linear-gradient(135deg,#0033a0 0%,#ffcc00 55%,#cc0001 100%)'],
        'IN' => ['primary'=>'#ff9933','secondary'=>'#138808','accent'=>'#000080','text'=>'#111827','gradient'=>'linear-gradient(135deg,#ff9933 0%,#ffffff 45%,#138808 100%)'],
        'TH' => ['primary'=>'#a51931','secondary'=>'#2d2a4a','accent'=>'#f4f5f8','text'=>'#111827','gradient'=>'linear-gradient(135deg,#a51931 0%,#2d2a4a 100%)'],
        'ID' => ['primary'=>'#ff0000','secondary'=>'#ffffff','accent'=>'#b91c1c','text'=>'#111827','gradient'=>'linear-gradient(135deg,#ff0000 0%,#ffffff 100%)'],
        'PH' => ['primary'=>'#0038a8','secondary'=>'#ce1126','accent'=>'#fcd116','text'=>'#111827','gradient'=>'linear-gradient(135deg,#0038a8 0%,#ce1126 65%,#fcd116 100%)'],
        'AE' => ['primary'=>'#00732f','secondary'=>'#ce1126','accent'=>'#000000','text'=>'#111827','gradient'=>'linear-gradient(135deg,#00732f 0%,#ffffff 45%,#ce1126 100%)'],
        'GB' => ['primary'=>'#012169','secondary'=>'#c8102e','accent'=>'#ffffff','text'=>'#111827','gradient'=>'linear-gradient(135deg,#012169 0%,#c8102e 100%)'],
        'UK' => ['primary'=>'#012169','secondary'=>'#c8102e','accent'=>'#ffffff','text'=>'#111827','gradient'=>'linear-gradient(135deg,#012169 0%,#c8102e 100%)'],
        'US' => ['primary'=>'#3c3b6e','secondary'=>'#b22234','accent'=>'#ffffff','text'=>'#111827','gradient'=>'linear-gradient(135deg,#3c3b6e 0%,#b22234 100%)'],
        'AU' => ['primary'=>'#00008b','secondary'=>'#ff0000','accent'=>'#ffffff','text'=>'#111827','gradient'=>'linear-gradient(135deg,#00008b 0%,#ff0000 100%)'],
    ];
    return $map[$iso2] ?? ['primary'=>'#2563eb','secondary'=>'#f8fafc','accent'=>'#f97316','text'=>'#111827','gradient'=>'linear-gradient(135deg,#2563eb 0%,#7c3aed 100%)'];
}
}

if (!function_exists('mj_v288_country_theme')) {
function mj_v288_country_theme(array $country = []): array {
    $iso = strtoupper((string)($country['iso2'] ?? $country['country_iso2'] ?? ''));
    $theme = mj_v288_country_theme_defaults($iso);
    $map = ['theme_primary'=>'primary','theme_secondary'=>'secondary','theme_accent'=>'accent','theme_text'=>'text','theme_gradient'=>'gradient'];
    $useDb = !isset($country['use_flag_theme']) || (int)$country['use_flag_theme'] !== 0;
    if ($useDb) {
        foreach ($map as $col=>$key) {
            if (!empty($country[$col])) { $theme[$key] = (string)$country[$col]; }
        }
    }
    $theme['class'] = 'country-theme-' . strtolower($iso ?: slugify((string)($country['name'] ?? 'global')));
    return $theme;
}
}

if (!function_exists('mj_v288_country_theme_style')) {
function mj_v288_country_theme_style(array $country = []): string {
    $t = mj_v288_country_theme($country);
    return '--country-primary:'.e($t['primary']).';--country-secondary:'.e($t['secondary']).';--country-accent:'.e($t['accent']).';--country-text:'.e($t['text']).';--country-gradient:'.e($t['gradient']).';';
}
}

if (!function_exists('mj_v288_status_label')) {
function mj_v288_status_label(?string $status): string {
    $s = strtolower(trim((string)$status));
    $map = [
        ''=>'Pending','submit'=>'Pending','submitted'=>'Pending','pending_review'=>'Pending Admin Review','pending'=>'Pending','review'=>'Pending',
        'need_info'=>'Need More Info','need_more_info'=>'Need More Info','more_info'=>'Need More Info',
        'approved'=>'Approved','active'=>'Active','published'=>'Active','paid'=>'Paid','completed'=>'Completed','success'=>'Approved',
        'rejected'=>'Rejected','reject'=>'Rejected','failed'=>'Failed','unpaid'=>'Unpaid','cancelled'=>'Cancelled','canceled'=>'Cancelled',
        'expired'=>'Expired','refunded'=>'Refunded','suspended'=>'Suspended','confirmed'=>'Confirmed','rescheduled'=>'Rescheduled','no_show'=>'No Show'
    ];
    return $map[$s] ?? ucwords(str_replace('_',' ', $s));
}
}

if (!function_exists('mj_v288_status_badge')) {
function mj_v288_status_badge(?string $status): string {
    $s = strtolower(trim((string)$status));
    $class = 'secondary';
    if (in_array($s, ['approved','active','published','paid','completed','success','confirmed'], true)) { $class = 'success'; }
    elseif (in_array($s, ['pending','submit','submitted','pending_review','review'], true)) { $class = 'warning text-dark'; }
    elseif (in_array($s, ['rejected','reject','failed','expired','suspended','cancelled','canceled','no_show'], true)) { $class = 'danger'; }
    elseif (in_array($s, ['need_info','need_more_info','more_info','rescheduled','unpaid'], true)) { $class = 'info text-dark'; }
    return '<span class="badge bg-'.$class.'">'.e(mj_v288_status_label($status)).'</span>';
}
}

if (!function_exists('mj_v288_count')) {
function mj_v288_count(string $table, string $where = '1=1', array $params = []): int {
    if (!table_exists($table)) { return 0; }
    try { $row = one('SELECT COUNT(*) c FROM `'.preg_replace('/[^a-zA-Z0-9_]/','',$table).'` WHERE '.$where, $params); return (int)($row['c'] ?? 0); }
    catch (Throwable $e) { return 0; }
}
}

if (!function_exists('mj_v288_sum')) {
function mj_v288_sum(string $table, string $column, string $where = '1=1', array $params = []): float {
    if (!table_exists($table) || !mj_has_col($table, $column)) { return 0.0; }
    try { $row = one('SELECT COALESCE(SUM(`'.preg_replace('/[^a-zA-Z0-9_]/','',$column).'`),0) s FROM `'.preg_replace('/[^a-zA-Z0-9_]/','',$table).'` WHERE '.$where, $params); return (float)($row['s'] ?? 0); }
    catch (Throwable $e) { return 0.0; }
}
}

if (!function_exists('mj_v288_ensure_schema')) {
function mj_v288_ensure_schema(): void {
    if (!mj_is_installed()) { return; }
    try { q("CREATE TABLE IF NOT EXISTS mj_company_page_settings (
        company_id BIGINT NOT NULL PRIMARY KEY,
        layout_style VARCHAR(80) DEFAULT 'modern_card',
        theme_primary VARCHAR(32) NULL,
        theme_secondary VARCHAR(32) NULL,
        theme_accent VARCHAR(32) NULL,
        cover_image VARCHAR(255) NULL,
        video_url VARCHAR(255) NULL,
        show_reviews TINYINT(1) NOT NULL DEFAULT 1,
        show_booking TINYINT(1) NOT NULL DEFAULT 0,
        seo_title VARCHAR(255) NULL,
        seo_description TEXT NULL,
        updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch(Throwable $e) {}
    try { q("CREATE TABLE IF NOT EXISTS mj_company_page_sections (
        id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
        company_id BIGINT NOT NULL,
        section_key VARCHAR(80) NOT NULL,
        section_title VARCHAR(255) NULL,
        section_content MEDIUMTEXT NULL,
        is_enabled TINYINT(1) NOT NULL DEFAULT 1,
        sort_order INT NOT NULL DEFAULT 0,
        updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        INDEX(company_id), INDEX(section_key)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch(Throwable $e) {}
    try { q("CREATE TABLE IF NOT EXISTS mj_company_booking_settings (
        company_id BIGINT NOT NULL PRIMARY KEY,
        is_enabled TINYINT(1) NOT NULL DEFAULT 0,
        booking_type VARCHAR(80) DEFAULT 'appointment',
        slot_duration INT NOT NULL DEFAULT 30,
        buffer_minutes INT NOT NULL DEFAULT 0,
        max_bookings_per_day INT NOT NULL DEFAULT 20,
        advance_days INT NOT NULL DEFAULT 30,
        same_day_booking TINYINT(1) NOT NULL DEFAULT 1,
        manual_approval TINYINT(1) NOT NULL DEFAULT 1,
        allow_reschedule TINYINT(1) NOT NULL DEFAULT 1,
        allow_cancel TINYINT(1) NOT NULL DEFAULT 1,
        business_hours_json TEXT NULL,
        closed_dates_json TEXT NULL,
        updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch(Throwable $e) {}
    try { q("CREATE TABLE IF NOT EXISTS mj_appointments (
        id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
        user_id BIGINT NULL,
        seller_user_id BIGINT NULL,
        company_id BIGINT NULL,
        listing_id BIGINT NULL,
        service_id BIGINT NULL,
        branch_id BIGINT NULL,
        customer_name VARCHAR(190) NULL,
        customer_email VARCHAR(190) NULL,
        customer_phone VARCHAR(80) NULL,
        appointment_datetime DATETIME NULL,
        duration_minutes INT NOT NULL DEFAULT 30,
        status VARCHAR(50) NOT NULL DEFAULT 'pending',
        note TEXT NULL,
        admin_note TEXT NULL,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        INDEX(user_id), INDEX(seller_user_id), INDEX(company_id), INDEX(status), INDEX(appointment_datetime)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch(Throwable $e) {}
    try { q("CREATE TABLE IF NOT EXISTS mj_admin_notes (
        id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
        admin_id BIGINT NULL,
        related_type VARCHAR(80) NOT NULL,
        related_id BIGINT NOT NULL,
        note TEXT NOT NULL,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        INDEX(related_type,related_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch(Throwable $e) {}
    try { q("CREATE TABLE IF NOT EXISTS mj_saved_searches (
        id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
        user_id BIGINT NOT NULL,
        title VARCHAR(190) NULL,
        query_json TEXT NULL,
        alert_enabled TINYINT(1) NOT NULL DEFAULT 1,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        INDEX(user_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch(Throwable $e) {}
    try { q("CREATE TABLE IF NOT EXISTS mj_system_run_logs (
        id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
        task_key VARCHAR(120) NOT NULL,
        status VARCHAR(50) NOT NULL DEFAULT 'success',
        message TEXT NULL,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        INDEX(task_key)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch(Throwable $e) {}
    $countryCols = [
        'theme_primary' => "VARCHAR(32) NULL", 'theme_secondary'=>"VARCHAR(32) NULL", 'theme_accent'=>"VARCHAR(32) NULL", 'theme_text'=>"VARCHAR(32) NULL", 'theme_gradient'=>"VARCHAR(255) NULL", 'use_flag_theme'=>"TINYINT(1) NOT NULL DEFAULT 1"
    ];
    if (table_exists('mj_countries')) { foreach ($countryCols as $c=>$def) { try { if (!mj_has_col('mj_countries', $c)) { q('ALTER TABLE mj_countries ADD COLUMN `'.$c.'` '.$def); } } catch(Throwable $e) {} } }
}
}

if (!function_exists('mj_v288_company_page_settings')) {
function mj_v288_company_page_settings(int $companyId): array {
    mj_v288_ensure_schema();
    $defaults = ['company_id'=>$companyId,'layout_style'=>'modern_card','theme_primary'=>'','theme_secondary'=>'','theme_accent'=>'','cover_image'=>'','video_url'=>'','show_reviews'=>1,'show_booking'=>0,'seo_title'=>'','seo_description'=>''];
    if ($companyId <= 0 || !table_exists('mj_company_page_settings')) { return $defaults; }
    try { $row = one('SELECT * FROM mj_company_page_settings WHERE company_id=? LIMIT 1', [$companyId]); return $row ? array_merge($defaults, $row) : $defaults; }
    catch(Throwable $e) { return $defaults; }
}
}

if (!function_exists('mj_v288_company_sections')) {
function mj_v288_company_sections(int $companyId): array {
    mj_v288_ensure_schema();
    if ($companyId <= 0 || !table_exists('mj_company_page_sections')) { return []; }
    try { return all_rows('SELECT * FROM mj_company_page_sections WHERE company_id=? AND is_enabled=1 ORDER BY sort_order,id', [$companyId]); }
    catch(Throwable $e) { return []; }
}
}

if (!function_exists('mj_v288_booking_settings')) {
function mj_v288_booking_settings(int $companyId): array {
    mj_v288_ensure_schema();
    $defaults = ['company_id'=>$companyId,'is_enabled'=>0,'booking_type'=>'appointment','slot_duration'=>30,'buffer_minutes'=>0,'max_bookings_per_day'=>20,'advance_days'=>30,'same_day_booking'=>1,'manual_approval'=>1,'allow_reschedule'=>1,'allow_cancel'=>1,'business_hours_json'=>'','closed_dates_json'=>''];
    if ($companyId <= 0 || !table_exists('mj_company_booking_settings')) { return $defaults; }
    try { $row = one('SELECT * FROM mj_company_booking_settings WHERE company_id=? LIMIT 1', [$companyId]); return $row ? array_merge($defaults, $row) : $defaults; }
    catch(Throwable $e) { return $defaults; }
}
}

if (!function_exists('mj_v288_user_timeline')) {
function mj_v288_user_timeline(int $userId, int $limit = 60): array {
    $items = [];
    $add = function($type,$title,$status,$date,$url='') use (&$items) { if ($date) { $items[]=['type'=>$type,'title'=>$title,'status'=>$status,'created_at'=>$date,'url'=>$url]; } };
    if ($userId <= 0) { return []; }
    try { if (table_exists('mj_listings')) foreach (all_rows('SELECT id,title,status,created_at FROM mj_listings WHERE user_id=? ORDER BY id DESC LIMIT 20',[$userId]) as $r) $add('listing','Listing: '.($r['title']??'Listing'),$r['status']??'', $r['created_at']??'', 'listing.php?id='.(int)$r['id']); } catch(Throwable $e) {}
    try { if (table_exists('mj_companies')) foreach (all_rows('SELECT id,name,status,created_at FROM mj_companies WHERE user_id=? ORDER BY id DESC LIMIT 20',[$userId]) as $r) $add('company','Company: '.($r['name']??'Company'),$r['status']??'', $r['created_at']??'', 'company.php?id='.(int)$r['id']); } catch(Throwable $e) {}
    foreach (['mj_upgrade_payment_proofs'=>'Upgrade proof','mj_payment_proofs'=>'Payment proof','mj_payment_requests'=>'Payment request','mj_invoices'=>'Invoice','mj_support_tickets'=>'Support ticket','mj_verification_requests'=>'Verification','mj_appointments'=>'Appointment'] as $table=>$label) {
        try { if (table_exists($table) && mj_has_col($table,'user_id')) foreach (all_rows('SELECT * FROM `'.preg_replace('/[^a-zA-Z0-9_]/','',$table).'` WHERE user_id=? ORDER BY id DESC LIMIT 20',[$userId]) as $r) $add($table,$label.' #'.($r['id']??''),$r['status']??($r['payment_status']??''), $r['created_at']??($r['submitted_at']??($r['created_on']??'')), ''); } catch(Throwable $e) {}
    }
    usort($items, function($a,$b){ return strcmp((string)$b['created_at'], (string)$a['created_at']); });
    return array_slice($items, 0, max(1, min(200, $limit)));
}
}

if (!function_exists('mj_v288_render_timeline')) {
function mj_v288_render_timeline(array $items): void {
    if (!$items) { echo '<div class="mj-empty-state p-4 text-center"><i class="bi bi-clock-history"></i><h5>No activity yet</h5><p class="text-muted mb-0">New listing, company, payment, support and booking activity will appear here.</p></div>'; return; }
    echo '<div class="mj-v288-timeline">';
    foreach ($items as $it) {
        echo '<div class="mj-v288-timeline-item"><div class="mj-v288-dot"></div><div class="mj-v288-line-card"><div class="d-flex justify-content-between gap-2 flex-wrap"><b>'.e($it['title'] ?? '').'</b>'.mj_v288_status_badge($it['status'] ?? '').'</div><small class="text-muted">'.e($it['created_at'] ?? '').'</small></div></div>';
    }
    echo '</div>';
}
}

if (!function_exists('mj_v288_link_scan')) {
function mj_v288_link_scan(string $baseDir): array {
    $result = [];
    $files = ['index.php','browse.php','companies.php','country.php','state.php','city.php','my-account.php','account-center.php','billing-payments.php','trust-verification.php','help-support.php','crm-leads.php','selling-center.php','buying-center.php','appointments.php','admin/dashboard.php','admin/users.php','admin/payments.php','admin/upgrade-payments.php','admin/approval-center.php','admin/system-health.php','admin/link-health.php'];
    foreach ($files as $f) { $result[] = ['file'=>$f,'exists'=>is_file(rtrim($baseDir,'/').'/'.$f)]; }
    return $result;
}
}

if (!function_exists('mj_v288_health_checks')) {
function mj_v288_health_checks(): array {
    $root = dirname(__DIR__);
    $checks = [];
    $checks[] = ['name'=>'PHP Version','value'=>PHP_VERSION,'ok'=>version_compare(PHP_VERSION,'8.0','>=')];
    $checks[] = ['name'=>'Config file','value'=>file_exists(__DIR__.'/config.php')?'Found':'Missing','ok'=>file_exists(__DIR__.'/config.php')];
    foreach (['assets/uploads','uploads/upgrade-payment-proofs','uploads/order-payment-proofs','uploads/quote-attachments'] as $d) {
        $path = $root.'/'.$d; $checks[] = ['name'=>$d,'value'=>(is_dir($path)?(is_writable($path)?'Writable':'Not writable'):'Missing'),'ok'=>is_dir($path) && is_writable($path)];
    }
    foreach (['mj_users','mj_listings','mj_companies','mj_payment_requests','mj_upgrade_payment_proofs','mj_invoices','mj_appointments','mj_company_page_settings'] as $t) {
        $checks[] = ['name'=>'Table '.$t,'value'=>table_exists($t)?'OK':'Missing','ok'=>table_exists($t)];
    }
    return $checks;
}
}

if (!function_exists('mj_v288_safe_admin_note_form')) {
function mj_v288_safe_admin_note_form(string $type, int $id): string {
    return '<form method="post" class="mt-2"><input type="hidden" name="csrf_token" value="'.e(csrf_token()).'"><input type="hidden" name="note_related_type" value="'.e($type).'"><input type="hidden" name="note_related_id" value="'.e($id).'"><div class="input-group input-group-sm"><input class="form-control" name="admin_note" placeholder="Add internal note"><button class="btn btn-dark">Save note</button></div></form>';
}
}

if (!function_exists('mj_v288_save_admin_note_from_post')) {
function mj_v288_save_admin_note_from_post(int $adminId): void {
    if ($_SERVER['REQUEST_METHOD'] !== 'POST' || empty($_POST['admin_note']) || empty($_POST['note_related_type']) || empty($_POST['note_related_id'])) { return; }
    verify_csrf(); mj_v288_ensure_schema();
    try { q('INSERT INTO mj_admin_notes(admin_id,related_type,related_id,note,created_at) VALUES(?,?,?,?,NOW())', [$adminId, substr((string)$_POST['note_related_type'],0,80), (int)$_POST['note_related_id'], trim((string)$_POST['admin_note'])]); flash('success','Admin note saved.'); }
    catch(Throwable $e) { flash('error','Unable to save note: '.$e->getMessage()); }
}
}
