<?php
declare(strict_types=1);

$allowedOrigins=['https://sodazw.co.zw','https://www.sodazw.co.zw'];
$origin=(string)($_SERVER['HTTP_ORIGIN']??'');
if($origin!==''&&in_array($origin,$allowedOrigins,true)){
    header('Access-Control-Allow-Origin: '.$origin);
    header('Vary: Origin');
    header('Access-Control-Allow-Methods: POST, OPTIONS');
    header('Access-Control-Allow-Headers: Content-Type');
    header('Access-Control-Max-Age: 600');
}
if(($_SERVER['REQUEST_METHOD']??'GET')==='OPTIONS'){
    if(!in_array($origin,$allowedOrigins,true)){http_response_code(403);exit;}
    http_response_code(204);exit;
}
header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store, max-age=0');
header('X-Content-Type-Options: nosniff');
header('Referrer-Policy: no-referrer');

function order_response(int $status,array $body):never{http_response_code($status);echo json_encode($body,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);exit;}
if(($_SERVER['REQUEST_METHOD']??'GET')!=='POST')order_response(405,['ok'=>false,'message'=>'POST requests only.']);
if(!in_array($origin,$allowedOrigins,true))order_response(403,['ok'=>false,'message'=>'This order source is not allowed.']);
$contentLength=(int)($_SERVER['CONTENT_LENGTH']??0);if($contentLength>32768)order_response(413,['ok'=>false,'message'=>'The order is too large.']);

require dirname(__DIR__).'/app/bootstrap.php';
if (!billing_schema_is_current()) order_response(503, ['ok'=>false, 'message'=>'Ordering is briefly unavailable while Soda ZW completes a system upgrade. Your cart is safe; please try again shortly.']);

try{
    $raw=file_get_contents('php://input');$data=json_decode((string)$raw,true,32,JSON_THROW_ON_ERROR);if(!is_array($data))throw new RuntimeException('Invalid order.');
    if(trim((string)($data['website']??''))!=='')order_response(200,['ok'=>true,'message'=>'Order received.']);
    $name=trim((string)($data['name']??''));$phone=trim((string)($data['phone']??''));$email=strtolower(trim((string)($data['email']??'')));$fulfilment=($data['fulfilment']??'Pickup')==='Delivery'?'Delivery':'Pickup';$deliveryZone=$fulfilment==='Delivery'?trim((string)($data['delivery_zone']??'')):'pickup';$address=trim((string)($data['address']??''));$payment=trim((string)($data['payment']??''));$notes=trim((string)($data['notes']??''));$idempotency=preg_replace('/[^a-zA-Z0-9-]/','',(string)($data['idempotency_key']??''));
    if(strlen($name)<2||strlen($name)>160)order_response(422,['ok'=>false,'message'=>'Please enter your full name.']);
    $phoneDigits=preg_replace('/\D+/','',$phone);if(strlen($phoneDigits)<7||strlen($phoneDigits)>15)order_response(422,['ok'=>false,'message'=>'Please enter a valid phone or WhatsApp number.']);if(str_starts_with($phoneDigits,'0'))$phoneDigits='263'.substr($phoneDigits,1);elseif(strlen($phoneDigits)===9&&str_starts_with($phoneDigits,'7'))$phoneDigits='263'.$phoneDigits;$phone='+'.$phoneDigits;
    if($email!==''&&!filter_var($email,FILTER_VALIDATE_EMAIL))order_response(422,['ok'=>false,'message'=>'Please enter a valid email address.']);
    if($fulfilment==='Delivery'&&($address===''||strlen($address)>255))order_response(422,['ok'=>false,'message'=>'Please enter your delivery area or address.']);
    if($fulfilment==='Delivery'&&!in_array($deliveryZone,['harare','outside_harare'],true))order_response(422,['ok'=>false,'message'=>'Please select Harare or outside-Harare delivery.']);
    if(strlen($payment)>100||strlen($notes)>1000||strlen($idempotency)<16||strlen($idempotency)>64)order_response(422,['ok'=>false,'message'=>'Please check the order details and try again.']);
    $incoming=$data['items']??[];if(!is_array($incoming)||count($incoming)<1||count($incoming)>30)order_response(422,['ok'=>false,'message'=>'Your cart must contain between 1 and 30 products.']);
    $requested=[];foreach($incoming as $item){$sku=strtoupper(trim((string)($item['sku']??'')));$quantity=(int)($item['quantity']??0);if(!preg_match('/^[A-Z0-9&-]{3,80}$/',$sku)||$quantity<1||$quantity>20)order_response(422,['ok'=>false,'message'=>'One of the cart items is invalid.']);$requested[$sku]=($requested[$sku]??0)+$quantity;if($requested[$sku]>20)order_response(422,['ok'=>false,'message'=>'The quantity requested is too high.']);}
    $allowedPayments=['Confirm later','Cash','EcoCash','Bank transfer','Paynow'];if(!in_array($payment,$allowedPayments,true))order_response(422,['ok'=>false,'message'=>'Please select a valid payment method.']);
    $existing=db()->prepare('SELECT id,order_number,total,payment_preference,fulfilment_method,delivery_fee FROM web_orders WHERE idempotency_key=? LIMIT 1');$existing->execute([$idempotency]);if($duplicate=$existing->fetch()){
        $duplicateResponse=['ok'=>true,'order_number'=>$duplicate['order_number'],'total'=>(float)$duplicate['total'],'duplicate'=>true];
        if($duplicate['payment_preference']==='Paynow'&&($duplicate['fulfilment_method']!=='Delivery'||(float)$duplicate['delivery_fee']>0)){
            try{$checkout=paynow_checkout_for_order((int)$duplicate['id']);$duplicateResponse['payment_url']=$checkout['payment_url'];$duplicateResponse['payment_status']=$checkout['status'];}catch(Throwable $paynowError){$duplicateResponse['payment_error']='Your order is saved, but online checkout could not start. Please continue on WhatsApp.';error_log('Soda ZW duplicate Paynow checkout error: '.$paynowError->getMessage());}
        }
        order_response(200,$duplicateResponse);
    }
    $ipHash=hash('sha256',(string)($_SERVER['REMOTE_ADDR']??'unknown'));$rate=db()->prepare('SELECT COUNT(*) FROM web_orders WHERE (client_ip_hash=? AND created_at>=DATE_SUB(NOW(),INTERVAL 1 HOUR)) OR (phone=? AND created_at>=DATE_SUB(NOW(),INTERVAL 24 HOUR))');$rate->execute([$ipHash,$phone]);if((int)$rate->fetchColumn()>=8)order_response(429,['ok'=>false,'message'=>'Too many recent orders. Please contact Soda ZW on WhatsApp.']);
    $placeholders=implode(',',array_fill(0,count($requested),'?'));$products=db()->prepare("SELECT id,sku,name,unit_price,tax_rate,active,track_stock,stock_quantity FROM products WHERE sku IN ({$placeholders}) AND active=1");$products->execute(array_keys($requested));$catalogue=[];foreach($products as $product)$catalogue[$product['sku']]=$product;if(count($catalogue)!==count($requested))order_response(422,['ok'=>false,'message'=>'A product in your cart is no longer available. Please refresh the shop.']);foreach($requested as $sku=>$quantity){$product=$catalogue[$sku];if((int)$product['track_stock']===1&&(float)$product['stock_quantity']<$quantity)order_response(409,['ok'=>false,'message'=>$product['name'].' does not have enough confirmed stock for this order. Please contact Soda ZW.']);}
    $lines=[];$subtotal=0.0;foreach($requested as $sku=>$quantity){$product=$catalogue[$sku];$price=(float)$product['unit_price'];$line=round($price*$quantity,2);$subtotal+=$line;$lines[]=['product_id'=>(int)$product['id'],'sku'=>$sku,'name'=>$product['name'],'quantity'=>$quantity,'unit_price'=>$price,'line_total'=>$line];}$subtotal=round($subtotal,2);$deliveryFee=$fulfilment==='Delivery'&&$deliveryZone==='harare'?10.00:0.00;$total=round($subtotal+$deliveryFee,2);
    db()->beginTransaction();
    $orderNumber='WEB-'.date('Ymd').'-'.strtoupper(substr(bin2hex(random_bytes(5)),0,8));
    $insert=db()->prepare('INSERT INTO web_orders (order_number,idempotency_key,customer_name,phone,email,fulfilment_method,delivery_address,payment_preference,notes,currency_code,subtotal,delivery_fee,total,client_ip_hash,user_agent) VALUES (?,?,?,?,?,?,?,?,?,"USD",?,?,?,?,?)');
    $insert->execute([$orderNumber,$idempotency,$name,$phone,$email?:null,$fulfilment,$address?:null,$payment?:null,$notes?:null,$subtotal,$deliveryFee,$total,$ipHash,substr((string)($_SERVER['HTTP_USER_AGENT']??''),0,255)]);
    $orderId=(int)db()->lastInsertId();
    $itemInsert=db()->prepare('INSERT INTO web_order_items (web_order_id,product_id,sku,product_name,quantity,unit_price,line_total) VALUES (?,?,?,?,?,?,?)');
    foreach($lines as $line)$itemInsert->execute([$orderId,$line['product_id'],$line['sku'],$line['name'],$line['quantity'],$line['unit_price'],$line['line_total']]);

    $customerId=null;
    if($email!==''){$findCustomer=db()->prepare('SELECT id FROM customers WHERE active=1 AND email=? LIMIT 1');$findCustomer->execute([$email]);$customerId=$findCustomer->fetchColumn()?:null;}
    if(!$customerId){$findCustomer=db()->prepare('SELECT id FROM customers WHERE active=1 AND (phone=? OR whatsapp=?) LIMIT 1');$findCustomer->execute([$phone,$phone]);$customerId=$findCustomer->fetchColumn()?:null;}
    if($customerId){
        db()->prepare('UPDATE customers SET phone=IF(phone IS NULL OR phone="",?,phone),whatsapp=IF(whatsapp IS NULL OR whatsapp="",?,whatsapp),email=IF(email IS NULL OR email="",?,email),address=IF(?<>"",?,address),preferred_payment=IF(?<>"",?,preferred_payment),last_contact_at=NOW() WHERE id=?')->execute([$phone,$phone,$email,$address,$address,$payment,$payment,$customerId]);
    }else{
        db()->prepare('INSERT INTO customers (name,email,phone,whatsapp,address,city,customer_type,preferred_payment,last_contact_at,notes) VALUES (?,?,?,?,?,"Harare","Household",?,NOW(),?)')->execute([$name,$email?:null,$phone,$phone,$address?:null,$payment?:null,'Created automatically from website order '.$orderNumber]);
        $customerId=(int)db()->lastInsertId();
    }
    db()->prepare('UPDATE web_orders SET customer_id=? WHERE id=?')->execute([$customerId,$orderId]);
    $ownerId=(int)db()->query("SELECT id FROM users WHERE active=1 ORDER BY FIELD(role,'owner','admin','staff'),id LIMIT 1")->fetchColumn();
    if(!$ownerId)throw new RuntimeException('The billing system has no active CRM owner.');
    $productSummary=implode(', ',array_slice(array_map(fn($line)=>$line['name'].' × '.$line['quantity'],$lines),0,3));
    db()->prepare('INSERT INTO crm_opportunities (customer_id,web_order_id,title,stage,source,value,currency_code,expected_close_date,next_follow_up_at,assigned_to,notes,created_by) VALUES (?, ?, ?, "new_enquiry", "Website", ?, "USD", CURDATE(), DATE_ADD(NOW(),INTERVAL 2 HOUR), ?, ?, ?)')->execute([$customerId,$orderId,'Website order '.$orderNumber,$total,$ownerId,'Items: '.$productSummary.($fulfilment==='Delivery'?' | '.($deliveryZone==='harare'?'Harare delivery $10':'Outside Harare delivery fee to confirm').' to '.$address:' | Pickup requested').($notes!==''?' | '.$notes:''),$ownerId]);
    $opportunityId=(int)db()->lastInsertId();
    if((int)(settings()['auto_invoice_web_orders']??1)===1){
        $invoiceNumber=reserve_unique_number('invoice');$issue=date('Y-m-d');$due=date('Y-m-d',strtotime('+'.max(0,(int)(settings()['default_due_days']??7)).' days'));$shareToken=bin2hex(random_bytes(32));$invoiceNotes='Created automatically from website order '.$orderNumber.($fulfilment==='Delivery'?($deliveryZone==='harare'?' · Harare delivery fee included at $10.':' · Outside-Harare delivery fee to be confirmed before issue.'):'').($notes!==''?' · '.$notes:'');
        db()->prepare('INSERT INTO documents (type,number,customer_id,issue_date,due_date,status,currency_code,subtotal,discount_type,discount_value,discount_total,tax_total,delivery_fee,total,notes,terms,customer_reference,order_source,fulfilment_method,delivery_address,share_token,share_enabled,created_by) VALUES ("invoice",?,?,?,? ,"draft","USD",? ,"fixed",0,0,0,?,?,?,?,?,"Website",?,?,?,1,?)')->execute([$invoiceNumber,$customerId,$issue,$due,$subtotal,$deliveryFee,$total,$invoiceNotes,(string)(settings()['invoice_terms']??''),$orderNumber,$fulfilment,$address?:null,$shareToken,$ownerId]);
        $invoiceId=(int)db()->lastInsertId();$itemInsert=db()->prepare('INSERT INTO document_items (document_id,product_id,description,quantity,unit_price,unit_cost,tax_rate,line_subtotal,line_tax,line_total,sort_order) SELECT ?,p.id,?, ?,?,p.cost_price,0,?,0,?,? FROM products p WHERE p.id=?');foreach($lines as $index=>$line)$itemInsert->execute([$invoiceId,$line['name'],$line['quantity'],$line['unit_price'],$line['line_total'],$line['line_total'],$index,$line['product_id']]);
        db()->prepare('UPDATE web_orders SET invoice_id=?,status="invoiced" WHERE id=?')->execute([$invoiceId,$orderId]);db()->prepare('UPDATE crm_opportunities SET document_id=?,stage="invoiced" WHERE id=?')->execute([$invoiceId,$opportunityId]);db()->prepare('INSERT INTO document_events (document_id,event_type,from_status,to_status,notes,created_by) VALUES (?,"created",NULL,"draft",?,?)')->execute([$invoiceId,'Created automatically from '.$orderNumber,$ownerId]);
    }
    db()->commit();
    audit('website_order_received','web_order',$orderId,$orderNumber);
    $response=['ok'=>true,'order_number'=>$orderNumber,'subtotal'=>$subtotal,'delivery_fee'=>$deliveryFee,'total'=>$total,'currency'=>'USD'];
    if($payment==='Paynow'){
        if($fulfilment==='Delivery'&&$deliveryZone!=='harare'){
            $response['payment_pending']=true;
            $response['message']='Your order is saved. Soda ZW will confirm the delivery fee before sending your Paynow payment link.';
        }else{
            try{$checkout=paynow_checkout_for_order($orderId);$response['payment_url']=$checkout['payment_url'];$response['payment_status']=$checkout['status'];}
            catch(Throwable $paynowError){$response['payment_error']='Your order is saved, but online checkout could not start. Please continue on WhatsApp.';error_log('Soda ZW Paynow checkout error: '.$paynowError->getMessage());}
        }
    }
    order_response(201,$response);
}catch(JsonException){order_response(400,['ok'=>false,'message'=>'The order could not be read.']);}catch(Throwable $e){if(db()->inTransaction())db()->rollBack();error_log('Soda ZW website order error: '.$e->getMessage());order_response(500,['ok'=>false,'message'=>'The order could not be saved right now. Please continue on WhatsApp.']);}
