<?php
/**
 * MJ Marketplace v3.0.4.1 Stable Access + Notification + Location helpers.
 * No v3.0.5 city importer. No customer-to-seller payment.
 */

if (!function_exists('mjv3041_slug')) {
function mjv3041_slug(string $text): string {
    if (function_exists('slugify')) { return slugify($text); }
    $text = strtolower(trim($text));
    $text = preg_replace('/[^a-z0-9]+/i', '-', $text);
    $text = trim((string)$text, '-');
    return $text !== '' ? $text : 'item';
}
}

if (!function_exists('mjv3041_table_exists')) {
function mjv3041_table_exists(string $table): bool {
    if (function_exists('table_exists')) { return table_exists($table); }
    try { $r = one('SELECT COUNT(*) c FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=?', [$table]); return (int)($r['c'] ?? 0) > 0; }
    catch (Throwable $e) { return false; }
}
}

if (!function_exists('mjv3041_column_exists')) {
function mjv3041_column_exists(string $table, string $column): bool {
    try { $r = one('SELECT COUNT(*) c FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? AND COLUMN_NAME=?', [$table, $column]); return (int)($r['c'] ?? 0) > 0; }
    catch (Throwable $e) { return false; }
}
}

if (!function_exists('mjv3041_columns')) {
function mjv3041_columns(string $table): array {
    try { $rows = all_rows('SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=?', [$table]); return array_map(static fn($r) => (string)$r['COLUMN_NAME'], $rows); }
    catch (Throwable $e) { return []; }
}
}

if (!function_exists('mjv3041_ensure_light_schema')) {
function mjv3041_ensure_light_schema(): void {
    static $done = false; if ($done) return; $done = true;
    if (!function_exists('q') || !function_exists('db')) { return; }
    try {
        q("CREATE TABLE IF NOT EXISTS mj_notifications (
            id BIGINT AUTO_INCREMENT PRIMARY KEY,
            user_id BIGINT NULL,
            admin_id BIGINT NULL,
            user_type VARCHAR(20) NULL,
            title VARCHAR(255) NOT NULL,
            message TEXT NULL,
            body TEXT NULL,
            type VARCHAR(80) NULL,
            priority VARCHAR(40) NOT NULL DEFAULT 'normal',
            link VARCHAR(500) NULL,
            action_url VARCHAR(500) NULL,
            url VARCHAR(500) NULL,
            is_read TINYINT(1) NOT NULL DEFAULT 0,
            is_popup_shown TINYINT(1) NOT NULL DEFAULT 0,
            popup_shown_at DATETIME NULL,
            read_at DATETIME NULL,
            meta_json LONGTEXT NULL,
            notification_key VARCHAR(191) NULL,
            dedupe_hash CHAR(40) NULL,
            source_type VARCHAR(80) NULL,
            source_id BIGINT NULL,
            lead_id BIGINT NULL,
            is_archived TINYINT(1) NOT NULL DEFAULT 0,
            archived_at DATETIME NULL,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            INDEX(user_id), INDEX(admin_id), INDEX(user_type), INDEX(is_read), INDEX(created_at)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    } catch (Throwable $e) {}
    try {
        q("CREATE TABLE IF NOT EXISTS mj_location_pending (
            id BIGINT AUTO_INCREMENT PRIMARY KEY,
            country_id INT NULL,
            state_id BIGINT NULL,
            city_id BIGINT NULL,
            country_name VARCHAR(180) NULL,
            state_name VARCHAR(180) NULL,
            city_name VARCHAR(180) NOT NULL,
            city_slug VARCHAR(220) NOT NULL,
            latitude DECIMAL(12,8) NULL,
            longitude DECIMAL(12,8) NULL,
            timezone VARCHAR(120) NULL,
            source VARCHAR(40) NOT NULL DEFAULT 'manual',
            status VARCHAR(40) NOT NULL DEFAULT 'pending',
            created_by BIGINT NULL,
            created_user_type VARCHAR(20) NULL,
            related_type VARCHAR(40) NULL,
            related_id BIGINT NULL,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            updated_at DATETIME NULL,
            KEY idx_pending_status(status), KEY idx_pending_country(country_id), KEY idx_pending_city(city_slug)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    } catch (Throwable $e) {}

    $add = static function(string $table, string $column, string $definition): void {
        try { if (mjv3041_table_exists($table) && !mjv3041_column_exists($table, $column)) { q('ALTER TABLE `'.preg_replace('/[^a-zA-Z0-9_]/','',$table).'` ADD COLUMN `'.preg_replace('/[^a-zA-Z0-9_]/','',$column).'` '.$definition); } }
        catch (Throwable $e) {}
    };
    foreach ([
        ['mj_notifications','user_type',"VARCHAR(20) NULL"], ['mj_notifications','admin_id',"BIGINT NULL"], ['mj_notifications','message',"TEXT NULL"], ['mj_notifications','body',"TEXT NULL"], ['mj_notifications','type',"VARCHAR(80) NULL"], ['mj_notifications','priority',"VARCHAR(40) NOT NULL DEFAULT 'normal'"], ['mj_notifications','link',"VARCHAR(500) NULL"], ['mj_notifications','action_url',"VARCHAR(500) NULL"], ['mj_notifications','url',"VARCHAR(500) NULL"], ['mj_notifications','is_popup_shown',"TINYINT(1) NOT NULL DEFAULT 0"], ['mj_notifications','popup_shown_at',"DATETIME NULL"], ['mj_notifications','read_at',"DATETIME NULL"], ['mj_notifications','meta_json',"LONGTEXT NULL"], ['mj_notifications','notification_key',"VARCHAR(191) NULL"], ['mj_notifications','dedupe_hash',"CHAR(40) NULL"], ['mj_notifications','source_type',"VARCHAR(80) NULL"], ['mj_notifications','source_id',"BIGINT NULL"], ['mj_notifications','lead_id',"BIGINT NULL"], ['mj_notifications','is_archived',"TINYINT(1) NOT NULL DEFAULT 0"], ['mj_notifications','archived_at',"DATETIME NULL"],
        ['mj_users','allow_deals',"TINYINT(1) NOT NULL DEFAULT 1"], ['mj_users','allow_leads',"TINYINT(1) NOT NULL DEFAULT 1"], ['mj_users','allow_crm',"TINYINT(1) NOT NULL DEFAULT 1"],
        ['mj_countries','iso2',"CHAR(2) NULL"], ['mj_countries','slug',"VARCHAR(180) NULL"], ['mj_countries','currency_code',"VARCHAR(8) NULL"], ['mj_countries','timezone_default',"VARCHAR(120) NULL"], ['mj_countries','phone_code',"VARCHAR(30) NULL"], ['mj_countries','flag_emoji',"VARCHAR(16) NULL"], ['mj_countries','is_active',"TINYINT(1) NOT NULL DEFAULT 1"],
        ['mj_states','state_code',"VARCHAR(50) NULL"], ['mj_states','slug',"VARCHAR(200) NULL"], ['mj_states','is_active',"TINYINT(1) NOT NULL DEFAULT 1"],
        ['mj_cities','slug',"VARCHAR(200) NULL"], ['mj_cities','latitude',"DECIMAL(12,8) NULL"], ['mj_cities','longitude',"DECIMAL(12,8) NULL"], ['mj_cities','timezone',"VARCHAR(120) NULL"], ['mj_cities','is_active',"TINYINT(1) NOT NULL DEFAULT 1"],
    ] as $x) { $add($x[0], $x[1], $x[2]); }
    try { if (mjv3041_table_exists('mj_notifications') && mjv3041_column_exists('mj_notifications','user_id')) { q('ALTER TABLE mj_notifications MODIFY user_id BIGINT NULL'); } } catch (Throwable $e) {}
    try { q("UPDATE mj_users SET allow_deals=1, allow_leads=1, allow_crm=1 WHERE allow_deals=0 OR allow_leads=0 OR allow_crm=0"); } catch (Throwable $e) {}
}
}

if (!function_exists('mjv3041_notify')) {
function mjv3041_notify(string $userType, ?int $userId, string $title, string $message = '', string $type = 'info', string $url = '', array $meta = []): int {
    if (function_exists('mj429_notify')) { return mj429_notify($userType, $userId, $title, $message, $type, $url, $meta); }
    mjv3041_ensure_light_schema();
    if (!mjv3041_table_exists('mj_notifications')) { return 0; }
    $cols = mjv3041_columns('mj_notifications');
    $data = [];
    if (in_array('user_type', $cols, true)) { $data['user_type'] = $userType; }
    if (in_array('user_id', $cols, true)) { $data['user_id'] = ($userType === 'user') ? ($userId ?: null) : null; }
    if (in_array('admin_id', $cols, true)) { $data['admin_id'] = ($userType === 'admin') ? ($userId ?: null) : null; }
    if (in_array('title', $cols, true)) { $data['title'] = $title; }
    if (in_array('message', $cols, true)) { $data['message'] = $message; }
    if (in_array('body', $cols, true)) { $data['body'] = $message; }
    if (in_array('type', $cols, true)) { $data['type'] = $type; }
    if (in_array('priority', $cols, true)) { $data['priority'] = in_array($type, ['lead','chat','payment','review'], true) ? 'high' : 'normal'; }
    if (in_array('link', $cols, true)) { $data['link'] = $url; }
    if (in_array('action_url', $cols, true)) { $data['action_url'] = $url; }
    if (in_array('url', $cols, true)) { $data['url'] = $url; }
    if (in_array('is_read', $cols, true)) { $data['is_read'] = 0; }
    if (in_array('is_popup_shown', $cols, true)) { $data['is_popup_shown'] = 0; }
    if (in_array('meta_json', $cols, true)) { $data['meta_json'] = $meta ? json_encode($meta, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) : null; }
    if (in_array('created_at', $cols, true)) { $data['created_at'] = date('Y-m-d H:i:s'); }
    if (!$data) { return 0; }
    try {
        $names = array_keys($data); $ph = implode(',', array_fill(0, count($names), '?'));
        q('INSERT INTO mj_notifications (`'.implode('`,`', $names).'`) VALUES ('.$ph.')', array_values($data));
        return (int)db()->lastInsertId();
    } catch (Throwable $e) { return 0; }
}
}

if (!function_exists('mjv3041_notify_user')) {
function mjv3041_notify_user(int $userId, string $title, string $message = '', string $type = 'info', string $url = '', array $meta = []): int { return mjv3041_notify('user', $userId, $title, $message, $type, $url, $meta); }
}
if (!function_exists('mjv3041_notify_admin')) {
function mjv3041_notify_admin(string $title, string $message = '', string $type = 'admin', string $url = '', array $meta = []): int { return mjv3041_notify('admin', null, $title, $message, $type, $url, $meta); }
}
if (!function_exists('mjv3041_notify_admins')) {
function mjv3041_notify_admins(string $title, string $message = '', string $type = 'admin', string $url = '', array $meta = []): void {
    mjv3041_ensure_light_schema();
    $sent = false;
    try {
        if (mjv3041_table_exists('mj_admin_users')) {
            $admins = all_rows("SELECT id FROM mj_admin_users WHERE status IN ('active','enabled','1') OR status IS NULL OR status='' LIMIT 100");
            if (!$admins) { $admins = all_rows('SELECT id FROM mj_admin_users LIMIT 50'); }
            foreach ($admins as $a) { mjv3041_notify('admin', (int)$a['id'], $title, $message, $type, $url, $meta); $sent = true; }
        }
    } catch (Throwable $e) {}
    if (!$sent) { mjv3041_notify_admin($title, $message, $type, $url, $meta); }
}
}

if (!function_exists('mjv3041_record_seller_lead')) {
function mjv3041_record_seller_lead(array $data): int {
    mjv3041_ensure_light_schema();
    try { if (function_exists('mjv304_create_seller_lead')) { return (int)mjv304_create_seller_lead($data); } } catch (Throwable $e) {}
    try {
        q("CREATE TABLE IF NOT EXISTS seller_leads (
            id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
            seller_user_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
            source_type VARCHAR(30) NOT NULL DEFAULT 'listing', source_id BIGINT UNSIGNED DEFAULT NULL, source_title VARCHAR(255) DEFAULT NULL, country VARCHAR(100) DEFAULT NULL,
            customer_name VARCHAR(160) DEFAULT NULL, customer_email VARCHAR(190) DEFAULT NULL, customer_phone VARCHAR(80) DEFAULT NULL, customer_message TEXT DEFAULT NULL,
            status VARCHAR(40) NOT NULL DEFAULT 'new', priority VARCHAR(20) NOT NULL DEFAULT 'normal', followup_at DATETIME DEFAULT NULL, last_activity_at DATETIME DEFAULT NULL,
            is_read TINYINT(1) NOT NULL DEFAULT 0, ip_address VARCHAR(80) DEFAULT NULL, user_agent VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT NULL,
            KEY idx_seller_status_created (seller_user_id,status,created_at), KEY idx_source (source_type,source_id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
        q("INSERT INTO seller_leads(seller_user_id,source_type,source_id,source_title,country,customer_name,customer_email,customer_phone,customer_message,status,priority,is_read,ip_address,user_agent,created_at,last_activity_at) VALUES(?,?,?,?,?,?,?,?,?,'new','normal',0,?,?,NOW(),NOW())", [
            (int)($data['seller_user_id'] ?? 0), (string)($data['source_type'] ?? 'listing'), !empty($data['source_id']) ? (int)$data['source_id'] : null, (string)($data['source_title'] ?? ''), (string)($data['country'] ?? ''),
            (string)($data['customer_name'] ?? ''), (string)($data['customer_email'] ?? ''), (string)($data['customer_phone'] ?? ''), (string)($data['customer_message'] ?? ''), $_SERVER['REMOTE_ADDR'] ?? '', substr((string)($_SERVER['HTTP_USER_AGENT'] ?? ''), 0, 255)
        ]);
        $id = (int)db()->lastInsertId();
        $seller = (int)($data['seller_user_id'] ?? 0); $type = (string)($data['source_type'] ?? 'lead'); $title = (string)($data['source_title'] ?? '');
        if ($seller > 0) { mjv3041_notify_user($seller, 'New '.ucfirst($type).' Lead', ($data['customer_name'] ?? 'Customer').' sent enquiry'.($title ? ' for '.$title : ''), 'lead', 'my-leads.php?lead_id='.$id, ['lead_id'=>$id,'source_type'=>$type]); }
        mjv3041_notify_admins('New '.ucfirst($type).' Lead', ($data['customer_name'] ?? 'Customer').' sent enquiry'.($title ? ' for '.$title : ''), 'lead', 'admin/leads.php?lead_id='.$id, ['lead_id'=>$id,'seller_user_id'=>$seller]);
        return $id;
    } catch (Throwable $e) { return 0; }
}
}

if (!function_exists('mjv3041_repair_seller_lead_owners')) {
function mjv3041_repair_seller_lead_owners(): void {
    try { if (mjv3041_table_exists('seller_leads') && mjv3041_table_exists('mj_deals')) { q("UPDATE seller_leads sl INNER JOIN mj_deals d ON sl.source_type IN ('deal','deal_enquiry') AND sl.source_id=d.id SET sl.seller_user_id=d.user_id WHERE (sl.seller_user_id IS NULL OR sl.seller_user_id=0) AND d.user_id IS NOT NULL"); } } catch (Throwable $e) {}
    try { if (mjv3041_table_exists('seller_leads') && mjv3041_table_exists('mj_listings')) { q("UPDATE seller_leads sl INNER JOIN mj_listings l ON sl.source_type IN ('listing','listing_enquiry') AND sl.source_id=l.id SET sl.seller_user_id=l.user_id WHERE (sl.seller_user_id IS NULL OR sl.seller_user_id=0) AND l.user_id IS NOT NULL"); } } catch (Throwable $e) {}
    try { if (mjv3041_table_exists('seller_leads') && mjv3041_table_exists('mj_companies')) { q("UPDATE seller_leads sl INNER JOIN mj_companies c ON sl.source_type IN ('company','company_enquiry') AND sl.source_id=c.id SET sl.seller_user_id=c.user_id WHERE (sl.seller_user_id IS NULL OR sl.seller_user_id=0) AND c.user_id IS NOT NULL"); } } catch (Throwable $e) {}
}
}

if (!function_exists('mjv3041_find_country')) {
function mjv3041_find_country($id = 0, string $name = '', string $iso2 = ''): ?array {
    try {
        if ($id) { $r = one('SELECT * FROM mj_countries WHERE id=? LIMIT 1', [(int)$id]); if ($r) return $r; }
        $iso2 = strtoupper(trim($iso2)); if ($iso2 !== '') { $r = one('SELECT * FROM mj_countries WHERE UPPER(iso2)=? LIMIT 1', [$iso2]); if ($r) return $r; }
        $name = trim($name); if ($name !== '') { $r = one('SELECT * FROM mj_countries WHERE LOWER(name)=LOWER(?) LIMIT 1', [$name]); if ($r) return $r; }
    } catch (Throwable $e) {}
    return null;
}
}

if (!function_exists('mjv3041_ensure_country')) {
function mjv3041_ensure_country(string $name, string $iso2 = '', string $timezone = '', string $currency = ''): int {
    mjv3041_ensure_light_schema();
    $country = mjv3041_find_country(0, $name, $iso2);
    if ($country) { return (int)$country['id']; }
    try {
        $slug = mjv3041_slug($name); $iso2 = strtoupper(substr(preg_replace('/[^A-Z]/i','', $iso2), 0, 2));
        if ($iso2 === '') { $iso2 = strtoupper(substr($slug, 0, 2)); }
        q('INSERT INTO mj_countries(iso2,name,slug,currency_code,timezone_default,is_active,created_at) VALUES(?,?,?,?,?,1,NOW())', [$iso2, $name, $slug, $currency ?: 'USD', $timezone ?: 'UTC']);
        return (int)db()->lastInsertId();
    } catch (Throwable $e) {
        try { $r = one('SELECT id FROM mj_countries WHERE slug=? OR name=? LIMIT 1', [mjv3041_slug($name), $name]); return (int)($r['id'] ?? 0); } catch (Throwable $e2) { return 0; }
    }
}
}

if (!function_exists('mjv3041_ensure_state')) {
function mjv3041_ensure_state(int $countryId, string $name, string $code = '', string $timezone = ''): int {
    if ($countryId <= 0 || trim($name) === '') { return 0; }
    mjv3041_ensure_light_schema(); $slug = mjv3041_slug($name);
    try { $r = one('SELECT id FROM mj_states WHERE country_id=? AND (slug=? OR LOWER(name)=LOWER(?)) LIMIT 1', [$countryId, $slug, $name]); if ($r) return (int)$r['id']; } catch (Throwable $e) {}
    try { q('INSERT INTO mj_states(country_id,name,state_code,slug,timezone,is_active) VALUES(?,?,?,?,?,1)', [$countryId, $name, $code ?: null, $slug, $timezone ?: null]); return (int)db()->lastInsertId(); }
    catch (Throwable $e) { try { $r = one('SELECT id FROM mj_states WHERE country_id=? AND slug=? LIMIT 1', [$countryId, $slug]); return (int)($r['id'] ?? 0); } catch (Throwable $e2) { return 0; } }
}
}

if (!function_exists('mjv3041_ensure_city')) {
function mjv3041_ensure_city(int $countryId, ?int $stateId, string $name, ?float $lat = null, ?float $lng = null, string $timezone = '', string $source = 'manual'): int {
    if ($countryId <= 0 || trim($name) === '') { return 0; }
    mjv3041_ensure_light_schema(); $slug = mjv3041_slug($name); $stateId = $stateId ?: null;
    try {
        $r = one('SELECT id FROM mj_cities WHERE country_id=? AND (state_id <=> ?) AND (slug=? OR LOWER(name)=LOWER(?)) LIMIT 1', [$countryId, $stateId, $slug, $name]);
        if ($r) { return (int)$r['id']; }
    } catch (Throwable $e) {}
    try {
        q('INSERT INTO mj_cities(country_id,state_id,name,slug,timezone,latitude,longitude,is_active) VALUES(?,?,?,?,?,?,?,1)', [$countryId, $stateId, $name, $slug, $timezone ?: null, $lat, $lng]);
        $id = (int)db()->lastInsertId();
    } catch (Throwable $e) {
        try { $r = one('SELECT id FROM mj_cities WHERE country_id=? AND slug=? LIMIT 1', [$countryId, $slug]); $id = (int)($r['id'] ?? 0); } catch (Throwable $e2) { $id = 0; }
    }
    if ($id && $source === 'manual') {
        try {
            $c = one('SELECT name FROM mj_countries WHERE id=?', [$countryId]) ?: [];
            $s = $stateId ? (one('SELECT name FROM mj_states WHERE id=?', [$stateId]) ?: []) : [];
            q('INSERT INTO mj_location_pending(country_id,state_id,city_id,country_name,state_name,city_name,city_slug,latitude,longitude,timezone,source,status,created_by,created_user_type,created_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,"pending",?,?,NOW())', [$countryId,$stateId,$id,$c['name']??null,$s['name']??null,$name,$slug,$lat,$lng,$timezone,'manual',(int)($_SESSION['user_id'] ?? $_SESSION['admin_id'] ?? 0), !empty($_SESSION['admin_id'])?'admin':'user']);
        } catch (Throwable $e) {}
    }
    return $id;
}
}
?>
