<?php
// MJ Marketplace v2.9.19 - user-to-admin service cart.
// Business rule: customer/buyer cannot pay seller/user through MJ Marketplace.

if (!function_exists('mj2919_cart_ensure_schema')) {
function mj2919_cart_ensure_schema(): void {
    if (!function_exists('q') || !mj_is_installed()) { return; }
    try {
        q("CREATE TABLE IF NOT EXISTS mj_admin_charge_cart (
            id BIGINT AUTO_INCREMENT PRIMARY KEY,
            user_id BIGINT NOT NULL,
            item_type VARCHAR(80) NOT NULL,
            target_type VARCHAR(80) NULL,
            target_id BIGINT NULL,
            title VARCHAR(190) NOT NULL,
            description TEXT NULL,
            quantity INT NOT NULL DEFAULT 1,
            unit_amount DECIMAL(12,2) NOT NULL DEFAULT 0,
            total_amount DECIMAL(12,2) NOT NULL DEFAULT 0,
            currency_code VARCHAR(10) NOT NULL DEFAULT 'SGD',
            duration_days INT NULL,
            status VARCHAR(40) NOT NULL DEFAULT 'cart',
            metadata_json MEDIUMTEXT NULL,
            batch_id BIGINT NULL,
            invoice_id BIGINT NULL,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            INDEX idx_user_status(user_id,status),
            INDEX idx_type(item_type),
            INDEX idx_target(target_type,target_id),
            INDEX idx_batch(batch_id),
            INDEX idx_created(created_at)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    } catch (Throwable $e) {}
    $cols = [
        'duration_days' => 'ALTER TABLE mj_admin_charge_cart ADD COLUMN duration_days INT NULL AFTER currency_code',
        'batch_id' => 'ALTER TABLE mj_admin_charge_cart ADD COLUMN batch_id BIGINT NULL AFTER metadata_json',
        'invoice_id' => 'ALTER TABLE mj_admin_charge_cart ADD COLUMN invoice_id BIGINT NULL AFTER batch_id'
    ];
    foreach ($cols as $col=>$sql) { try { if (!mj_column_exists('mj_admin_charge_cart', $col)) { q($sql); } } catch (Throwable $e) {} }
    try {
        $defaults = [
            'admin_service_cart_enabled' => '1',
            'deal_featured_charge_amount' => setting('listing_feature_charge_amount', '10.00'),
            'deal_sponsored_charge_amount' => setting('listing_sponsor_charge_amount', '15.00'),
            'deal_promotion_default_days' => '7',
            'deal_promotion_max_days' => '90',
            'extra_deal_slot_charge_amount' => '5.00',
            'deal_renewal_charge_amount' => '5.00',
            'deal_homepage_charge_amount' => '25.00',
            'deal_bump_charge_amount' => '3.00',
            'deal_urgent_charge_amount' => '3.00',
            'cart_abandoned_reminder_days' => '1,3,7'
        ];
        foreach ($defaults 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) {}
        }
    } catch (Throwable $e) {}
}
}

if (!function_exists('mj2919_cart_currency')) {
function mj2919_cart_currency(int $userId=0): string {
    $currency = setting('listing_upgrade_currency','SGD') ?: 'SGD';
    if ($userId > 0) {
        try {
            $u = one('SELECT c.currency_code FROM mj_users u LEFT JOIN mj_countries c ON c.id=u.country_id WHERE u.id=? LIMIT 1', [$userId]);
            if (!empty($u['currency_code'])) { $currency = (string)$u['currency_code']; }
        } catch (Throwable $e) {}
    }
    return strtoupper(trim($currency)) ?: 'SGD';
}
}

if (!function_exists('mj2919_cart_count')) {
function mj2919_cart_count(int $userId): int {
    try { mj2919_cart_ensure_schema(); return safe_count('SELECT COUNT(*) c FROM mj_admin_charge_cart WHERE user_id=? AND status="cart"', [$userId]); } catch (Throwable $e) { return 0; }
}
}

if (!function_exists('mj2919_cart_items')) {
function mj2919_cart_items(int $userId, string $status='cart'): array {
    mj2919_cart_ensure_schema();
    try { return all_rows('SELECT * FROM mj_admin_charge_cart WHERE user_id=? AND status=? ORDER BY id DESC LIMIT 200', [$userId,$status]); } catch (Throwable $e) { return []; }
}
}

if (!function_exists('mj2919_cart_totals')) {
function mj2919_cart_totals(array $items, string $currency='SGD'): array {
    $subtotal = 0.0; $count = 0;
    foreach ($items as $it) { $subtotal += (float)($it['total_amount'] ?? 0); $count += max(1,(int)($it['quantity'] ?? 1)); $currency = (string)($it['currency_code'] ?? $currency); }
    $taxEnabled = setting('payment_cart_tax_enabled', setting('billing_tax_enabled','0')) === '1';
    $taxRate = $taxEnabled ? max(0, (float)setting('payment_cart_default_tax_rate', setting('billing_default_tax_rate','0'))) : 0;
    $tax = round($subtotal * $taxRate / 100, 2);
    return ['count'=>$count,'subtotal'=>$subtotal,'tax'=>$tax,'total'=>$subtotal+$tax,'currency'=>$currency];
}
}

if (!function_exists('mj2919_user_deal_options')) {
function mj2919_user_deal_options(int $userId): array {
    if (function_exists('mj_v300_ensure_schema')) { mj_v300_ensure_schema(); }
    if (!table_exists('mj_deals')) { return []; }
    try { return all_rows('SELECT id,title,status,is_featured,is_sponsored,featured_until,sponsored_until FROM mj_deals WHERE user_id=? ORDER BY id DESC LIMIT 100', [$userId]); } catch (Throwable $e) { return []; }
}
}

if (!function_exists('mj2919_cart_add')) {
function mj2919_cart_add(int $userId, array $post): int {
    mj2919_cart_ensure_schema();
    if (setting('admin_service_cart_enabled','1') !== '1') { throw new Exception('Cart is disabled by admin.'); }
    $type = trim((string)($post['cart_item_type'] ?? ''));
    $currency = mj2919_cart_currency($userId);
    $title = ''; $desc = ''; $qty = 1; $unit = 0.0; $targetType = null; $targetId = null; $days = null; $meta = [];
    $extraMin = max(1, (int)setting('extra_slot_min_qty','1'));
    $extraMax = max($extraMin, (int)setting('extra_slot_max_qty','100'));
    if ($type === 'extra_listing_slot') {
        $qty = max($extraMin, min($extraMax, (int)($post['quantity'] ?? 1)));
        $unit = max(0.01, (float)setting('extra_listing_slot_charge_amount','5.00'));
        $title = 'Extra Listing Slots';
        $desc = 'Increase your listing limit by '.$qty.' slot(s) after payment approval.';
    } elseif ($type === 'extra_company_slot') {
        $qty = max($extraMin, min($extraMax, (int)($post['quantity'] ?? 1)));
        $unit = max(0.01, (float)setting('extra_company_slot_charge_amount','5.00'));
        $title = 'Extra Company Slots';
        $desc = 'Increase your company limit by '.$qty.' slot(s) after payment approval.';
    } elseif ($type === 'extra_deal_slot') {
        $qty = max($extraMin, min($extraMax, (int)($post['quantity'] ?? 1)));
        $unit = max(0.01, (float)setting('extra_deal_slot_charge_amount','5.00'));
        $title = 'Extra Deal Slots';
        $desc = 'Increase your deal limit by '.$qty.' slot(s) after payment approval.';
    } elseif (in_array($type, ['deal_featured','deal_sponsored','deal_homepage','deal_bump','deal_urgent','deal_renewal'], true)) {
        if (!table_exists('mj_deals')) { throw new Exception('Deals module is not installed.'); }
        $targetId = (int)($post['deal_id'] ?? 0);
        $deal = $targetId > 0 ? one('SELECT id,title,user_id FROM mj_deals WHERE id=? AND user_id=? LIMIT 1', [$targetId,$userId]) : null;
        if (!$deal) { throw new Exception('Please select one of your deals.'); }
        $maxDays = max(1, (int)setting('deal_promotion_max_days','90'));
        $days = max(1, min($maxDays, (int)($post['duration_days'] ?? setting('deal_promotion_default_days','7'))));
        $qty = $days;
        $opts = function_exists('mj_v300_deal_upgrade_options') ? mj_v300_deal_upgrade_options() : [];
        $opt = $opts[$type] ?? ['label'=>'Deal Promotion','setting'=>'deal_featured_charge_amount','default'=>'10.00'];
        $unit = max(0.01, (float)setting((string)$opt['setting'], (string)$opt['default']));
        $targetType = 'deal';
        $title = (string)$opt['label'];
        $desc = (string)$deal['title'].' · '.$days.' day(s). Activates after payment approval.';
        $meta = ['deal_title'=>(string)$deal['title']];
    } else {
        throw new Exception('Please select a valid cart item.');
    }
    $total = round($unit * $qty, 2);
    if ($total <= 0) { throw new Exception('Cart amount must be greater than zero.'); }
    q('INSERT INTO mj_admin_charge_cart(user_id,item_type,target_type,target_id,title,description,quantity,unit_amount,total_amount,currency_code,duration_days,status,metadata_json,created_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,"cart",?,NOW())', [
        $userId, $type, $targetType, $targetId, $title, $desc, $qty, $unit, $total, $currency, $days, json_encode($meta)
    ]);
    return (int)db()->lastInsertId();
}
}

if (!function_exists('mj2919_cart_remove')) {
function mj2919_cart_remove(int $userId, int $cartId): void {
    mj2919_cart_ensure_schema();
    q('DELETE FROM mj_admin_charge_cart WHERE id=? AND user_id=? AND status="cart"', [$cartId,$userId]);
}
}

if (!function_exists('mj2919_cart_clear')) {
function mj2919_cart_clear(int $userId): void {
    mj2919_cart_ensure_schema();
    q('DELETE FROM mj_admin_charge_cart WHERE user_id=? AND status="cart"', [$userId]);
}
}

if (!function_exists('mj2919_create_invoice_from_cart')) {
function mj2919_create_invoice_from_cart(int $userId, array $post): int {
    mj2919_cart_ensure_schema();
    mj291_payment_ensure_schema();
    $selected = isset($post['cart_ids']) && is_array($post['cart_ids']) ? array_values(array_filter(array_map('intval', $post['cart_ids']))) : [];
    if (isset($post['from_cart_form']) && !$selected) { throw new Exception('Please select at least one cart item.'); }
    $params = [$userId]; $where = 'user_id=? AND status="cart"';
    if ($selected) { $where .= ' AND id IN ('.implode(',', array_fill(0,count($selected),'?')).')'; $params = array_merge($params,$selected); }
    $items = all_rows('SELECT * FROM mj_admin_charge_cart WHERE '.$where.' ORDER BY id ASC LIMIT 200', $params);
    if (!$items) { throw new Exception('Your cart is empty.'); }
    $totals = mj2919_cart_totals($items, mj2919_cart_currency($userId));
    $currency = (string)$totals['currency']; $subtotal = (float)$totals['subtotal']; $tax = (float)$totals['tax']; $total = (float)$totals['total'];
    $note = trim((string)($post['payment_note'] ?? ''));
    $countryId = 0; try { $u = one('SELECT country_id FROM mj_users WHERE id=? LIMIT 1', [$userId]); $countryId = (int)($u['country_id'] ?? 0); } catch (Throwable $e) {}
    q('INSERT INTO mj_invoices(user_id,company_id,invoice_type,title,amount,tax_amount,total_amount,currency_code,status,due_date,created_at) VALUES(?,NULL,"proforma","Marketplace service cart",?,?,?,? ,"invoice_created",DATE_ADD(CURDATE(), INTERVAL 7 DAY),NOW())', [$userId,$subtotal,$tax,$total,$currency]);
    $invoiceId = (int)db()->lastInsertId(); $invoiceNo = mj291_next_doc_no('INV',$invoiceId,$currency); q('UPDATE mj_invoices SET invoice_no=? WHERE id=?', [$invoiceNo,$invoiceId]);
    q('INSERT INTO mj_payment_batches(batch_no,invoice_id,user_id,country_id,currency_code,subtotal_amount,tax_amount,total_amount,note,status,created_at) VALUES(NULL,?,?,?,?,?,?,?,? ,"invoice_created",NOW())', [$invoiceId,$userId,$countryId?:null,$currency,$subtotal,$tax,$total,$note]);
    $batchId = (int)db()->lastInsertId(); $batchNo = mj291_next_doc_no('PAY',$batchId,$currency); q('UPDATE mj_payment_batches SET batch_no=? WHERE id=?', [$batchNo,$batchId]);
    try { q('UPDATE mj_invoices SET batch_id=? WHERE id=?', [$batchId,$invoiceId]); } catch (Throwable $e) {}
    foreach ($items as $ci) {
        $itemType = (string)$ci['item_type']; $itemId = (int)($ci['target_id'] ?? 0); $label = (string)$ci['title']; $desc = (string)$ci['description'];
        if ($itemType === 'extra_listing_slot' || $itemType === 'extra_company_slot') {
            $slotType = $itemType === 'extra_company_slot' ? 'company' : 'listing';
            $itemId = mj291_create_limit_request_for_batch($userId, $slotType, (int)$ci['quantity'], (float)$ci['unit_amount'], $currency, $batchId, $invoiceId, $note, 'invoice_created');
            $itemType = 'limit_upgrade';
        }
        q('INSERT INTO mj_payment_batch_items(batch_id,user_id,item_type,item_id,item_label,item_description,listing_id,company_id,quantity,unit_amount,total_amount,currency_code,status,created_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,? ,"invoice_created",NOW())', [
            $batchId,$userId,$itemType,$itemId,$label,$desc,null,null,(int)$ci['quantity'],(float)$ci['unit_amount'],(float)$ci['total_amount'],$currency
        ]);
        q('INSERT INTO mj_invoice_items(invoice_id,user_id,item_type,item_id,description,quantity,unit_amount,total_amount,currency_code,created_at) VALUES(?,?,?,?,?,?,?,?,?,NOW())', [
            $invoiceId,$userId,$itemType,$itemId,trim($label.' - '.$desc),(int)$ci['quantity'],(float)$ci['unit_amount'],(float)$ci['total_amount'],$currency
        ]);
        q('UPDATE mj_admin_charge_cart SET status="invoiced", batch_id=?, invoice_id=?, updated_at=NOW() WHERE id=? AND user_id=?', [$batchId,$invoiceId,(int)$ci['id'],$userId]);
    }
    if (function_exists('mj263_notify')) { mj263_notify($userId, null, 'cart_invoice_created', 'Cart invoice generated', 'Your service cart invoice '.$invoiceNo.' is ready. Please review and pay.', 'billing-payments.php?tab=invoices', 'normal', true); }
    return $batchId;
}
}

if (!function_exists('mj2919_admin_cart_summary')) {
function mj2919_admin_cart_summary(): array {
    mj2919_cart_ensure_schema();
    $out = ['open_carts'=>0,'open_amount'=>0,'invoiced_today'=>0];
    try { $r=one('SELECT COUNT(DISTINCT user_id) c, COALESCE(SUM(total_amount),0) amt FROM mj_admin_charge_cart WHERE status="cart"'); $out['open_carts']=(int)($r['c']??0); $out['open_amount']=(float)($r['amt']??0); } catch(Throwable $e) {}
    try { $r=one('SELECT COUNT(*) c FROM mj_admin_charge_cart WHERE status="invoiced" AND DATE(updated_at)=CURDATE()'); $out['invoiced_today']=(int)($r['c']??0); } catch(Throwable $e) {}
    return $out;
}
}
