<?php
declare(strict_types=1);
if (!defined('STORE_ROOT')) { http_response_code(403); exit; }
function accountHandler(string $action, array $in): void {
$uid = App::requireAuth();
if ($action === 'get_orders') {
$orders = [];
try {
$rows = DB::all(
"SELECT id, COALESCE(reference, order_ref) AS reference, COALESCE(total, subtotal) AS total, COALESCE(status, status_label) AS status, shipping_method, tracking_number, carrier, created_at FROM orders WHERE user_id = :uid ORDER BY created_at DESC LIMIT 50",
[':uid' => $uid]
);
foreach ($rows as $r) {
$orders[] = [
'id' => (int)$r['id'],
'reference' => $r['reference'] ?? '',
'total' => number_format((float)($r['total'] ?? 0), 2),
'status' => ucfirst($r['status'] ?? 'pending'),
'shipping' => $r['shipping_method'] ?? 'standard',
'tracking' => $r['tracking_number'] ?? '',
'carrier' => $r['carrier'] ?? '',
'date' => date('M j, Y', strtotime($r['created_at'])),
];
}
} catch (\Throwable $e) {
error_log('[Account] get_orders: ' . $e->getMessage());
}
App::ok(['orders' => $orders]);
}
if ($action === 'get_reviews') {
$reviews = [];
try {
$rows = DB::all(
"SELECT id, title, body, rating, is_approved, created_at FROM reviews WHERE user_id = :uid ORDER BY created_at DESC LIMIT 50",
[':uid' => $uid]
);
foreach ($rows as $r) {
$reviews[] = [
'id' => (int)$r['id'],
'title' => Crypt::d($r['title'] ?? '') ?: ($r['title'] ?? ''),
'body' => Crypt::d($r['body'] ?? '') ?: ($r['body'] ?? ''),
'rating' => (int)($r['rating'] ?? 0),
'is_approved' => (bool)($r['is_approved'] ?? false),
'date' => date('M j, Y', strtotime($r['created_at'])),
];
}
} catch (\Throwable $e) {
error_log('[Account] get_reviews: ' . $e->getMessage());
}
App::ok(['reviews' => $reviews]);
}
if ($action === 'get_tickets') {
$tickets = [];
try {
$rows = DB::all(
"SELECT id, subject, status, created_at FROM support_tickets WHERE customer_id = :uid ORDER BY created_at DESC LIMIT 50",
[':uid' => $uid]
);
foreach ($rows as $r) {
$decSubject = Crypt::d($r['subject'] ?? '');
$tickets[] = [
'id' => (int)$r['id'],
'subject' => $decSubject ?: ($r['subject'] ?? ''),
'status' => $r['status'] ?? 'open',
'body' => '',
'date' => date('M j, Y', strtotime($r['created_at'])),
];
}
} catch (\Throwable $e) {
error_log('[Account] get_tickets: ' . $e->getMessage());
}
App::ok(['tickets' => $tickets]);
}
if ($action === 'create_ticket') {
Security::enforceCSRF();
$openCount = (int)DB::val(
"SELECT COUNT(*) FROM support_tickets WHERE customer_id = :uid AND status IN ('open','awaiting_reply')",
[':uid' => $uid]
);
if ($openCount >= 3) {
App::err('Maximum 3 open tickets allowed. Please wait for a response.', 429);
}
$typeCode = trim($in['type_code'] ?? '');
$subject = trim($in['subject'] ?? '');
$body = trim($in['body'] ?? $in['message'] ?? '');
$validTypes = ['A3F1B2','C7D4E9','B8E2A5','D1F6C3','E4A9B7','F2C8D6'];
if ($typeCode && !in_array($typeCode, $validTypes, true)) {
App::err('Invalid ticket type.', 400);
}
if (!$subject || !$body) {
App::err('Subject and message are required.', 400);
}
try {
$ticketRef = 'TK-' . strtoupper(bin2hex(random_bytes(5)));
DB::run(
"INSERT INTO support_tickets (ticket_ref, customer_id, subject, status, created_at) VALUES (:ref, :uid, :subj, 'open', NOW())",
[':ref' => $ticketRef, ':uid' => $uid, ':subj' => Crypt::encrypt($subject, Crypt::DOMAIN_USER)]
);
$ticketId = DB::lastId();
DB::run(
"INSERT INTO support_replies (ticket_id, sender_type, sender_name, message, created_at) VALUES (:tid, 'customer', :sn, :msg, NOW())",
[':tid' => $ticketId, ':sn' => Crypt::encrypt('Customer', Crypt::DOMAIN_USER), ':msg' => Crypt::encrypt($body, Crypt::DOMAIN_USER)]
);
App::ok(['success' => true, 'ticket_ref' => $ticketRef]);
} catch (\Throwable $e) {
error_log('[Account] create_ticket: ' . $e->getMessage());
App::err('Could not create ticket.', 500);
}
}
if ($action === 'update_profile') {
Security::enforceCSRF();
try {
$fields = [
'name' => Crypt::encrypt(trim($in['name'] ?? ''), Crypt::DOMAIN_USER),
'phone' => Crypt::encrypt(trim($in['phone'] ?? ''), Crypt::DOMAIN_USER),
'address' => Crypt::encrypt(trim($in['address'] ?? ''), Crypt::DOMAIN_USER),
'city' => Crypt::encrypt(trim($in['city'] ?? ''), Crypt::DOMAIN_USER),
'province' => trim($in['province'] ?? ''),
'postal_code' => Crypt::encrypt(trim($in['postal'] ?? ''), Crypt::DOMAIN_USER),
'country' => trim($in['country'] ?? 'CA'),
];
DB::run(
"UPDATE users SET name = :name, phone = :phone, address = :addr, city = :city, province = :prov, postal_code = :pc, country = :co WHERE id = :uid",
['name' => $fields['name'], ':phone' => $fields['phone'], ':addr' => $fields['address'], ':city' => $fields['city'], ':prov' => $fields['province'], ':pc' => $fields['postal_code'], ':co' => $fields['country'], ':uid' => $uid]
);
App::ok(['success' => true]);
} catch (\Throwable $e) {
error_log('[Account] update_profile: ' . $e->getMessage());
App::err('Update failed.', 500);
}
}
App::err('Unknown account action', 404);
}
