<?php
/**
 * ivr.php — Windshields To Go USA · Twilio TwiML IVR Order System
 * Upload to: /home/auto11/public_html/ivr/ivr.php
 *
 * Twilio webhook URL: https://autoglasshosting.com/ivr/ivr.php
 *
 * Flow: Welcome+ZIP → Year → Make → Model → Style → Glass
 *       → First → Last → Street → City → State → Phone → Email
 *       → PO/RO → Unit → Notes → Write order → SMS + Email VIN link
 *
 * Account routing by Twilio "To" param (original RC DNIS passed through):
 *   +18778072201 → PTL   (Penske)
 *   +18778457544 → LINDE
 *   +18772240909 → LINCARE
 *
 * STT: Deepgram Nova-2 via Twilio <Gather>
 * Press 9 at any time to start over
 * Press 0 at any time to transfer to live agent
 */

// ─── CONFIG ───────────────────────────────────────────────────────────────────
$config = require '/home/auto11/var/config.php';

define('TWILIO_ACCOUNT_SID', $config['twilio_account_sid'] ?? '');
define('TWILIO_API_KEY_SID', $config['twilio_api_key_sid'] ?? '');
define('TWILIO_API_SECRET',  $config['twilio_api_secret']  ?? '');
define('TWILIO_NUMBER',      $config['twilio_number']      ?? '');
define('DEEPGRAM_API_KEY',   $config['deepgram_api_key']   ?? '');

define('RC_CLIENT_ID',       'XH2IPXECRWdczFx0giHgxh');
define('RC_CLIENT_SECRET',   'bOEeTScZ7pwepvzW5tA9gvXa1pQNT1zRZbgSyNBWJap8');
define('RC_SERVER',          'https://platform.ringcentral.com');
define('RC_SMS_FROM',        '+18059785161');

define('DB_HOST',  'localhost');
define('DB_USER',  'windshi_quote');
define('DB_PASS',  $config['db_password'] ?? '');
define('DB_NAME',  'windshi_main');

define('IVR_COMPANY',    'Windshields To Go USA');
define('IVR_TRANSFER',   '+18005494470');
define('PROMPT_BASE',    'https://autoglasshosting.com/ivr/prompts/');
define('VIN_LINK_BASE',  'https://autoglasshosting.com/ivr/vin.php');
define('W2G_EMAIL',      'w2gusa@gmail.com');
define('SESSION_DIR',    '/tmp/ivr_sessions');
define('LOG_FILE',       '/tmp/ivr_twilio.log');

// Account profiles keyed by DNIS
$ACCOUNTS = [
    '+18778072201' => ['code' => 'PTL',     'company' => 'Penske',  'ask_po' => true,  'po_prefill' => '',         'aff_id' => 0],
    '+18778457544' => ['code' => 'LINDE',   'company' => 'Linde',   'ask_po' => true,  'po_prefill' => '',         'aff_id' => 0],
    '+18772240909' => ['code' => 'LINCARE', 'company' => 'Lincare', 'ask_po' => true,  'po_prefill' => '16020568', 'aff_id' => 0],
];
$DEFAULT_ACCOUNT = ['code' => 'W2G', 'company' => '', 'ask_po' => true, 'po_prefill' => '', 'ask_unit' => true, 'aff_id' => 0];

// ─── BOOTSTRAP ────────────────────────────────────────────────────────────────
error_reporting(0);
if (!is_dir(SESSION_DIR)) mkdir(SESSION_DIR, 0700, true);

function ivr_log($msg) {
    file_put_contents(LOG_FILE, date('[Y-m-d H:i:s] ') . $msg . "\n", FILE_APPEND);
}

// ─── VALIDATE TWILIO REQUEST ──────────────────────────────────────────────────
function validate_twilio() {
    // Basic validation — check expected Twilio params present
    if (empty($_POST['CallSid']) && empty($_GET['CallSid'])) {
        ivr_log('WARNING: Request missing CallSid — possible non-Twilio request');
    }
}

// ─── SESSION ──────────────────────────────────────────────────────────────────
function sess_path($id) {
    return SESSION_DIR . '/' . preg_replace('/[^a-zA-Z0-9_-]/', '_', $id) . '.json';
}
function sess_load($id) {
    $f = sess_path($id);
    return file_exists($f) ? (json_decode(file_get_contents($f), true) ?: []) : [];
}
function sess_save($id, $data) {
    file_put_contents(sess_path($id), json_encode($data));
}
function sess_del($id) {
    $f = sess_path($id);
    if (file_exists($f)) unlink($f);
}

// ─── NAGS PART LOOKUP ────────────────────────────────────────────────────────
function lookup_nags($year, $make, $model, $style, $glass, $zip) {
    $opening_map = [
        'windshield' => 'WS', 'driver' => 'DR', 'passenger' => 'DR',
        'rear' => 'BK', 'back' => 'BK', 'quarter' => 'QT',
    ];
    $opening = 'WS';
    $glass_lower = strtolower($glass);
    foreach ($opening_map as $k => $v) {
        if (strpos($glass_lower, $k) !== false) { $opening = $v; break; }
    }

    $url = 'https://autoglasshosting.com/ivr/proxy_nags_lookup.php'
        . '?year='    . urlencode($year)
        . '&make='    . urlencode($make)
        . '&model='   . urlencode($model)
        . '&style='   . urlencode($style)
        . '&opening=' . urlencode($opening)
        . '&zip='     . urlencode($zip);

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 20,
        CURLOPT_SSL_VERIFYPEER => false,
    ]);
    $body = curl_exec($ch);
    curl_close($ch);
    $data = json_decode($body, true);
    ivr_log("NAGS lookup $year $make $model '$style' opening=$opening: " . substr($body, 0, 200));
    return $data ?: [];
}
function base_url() {
    $proto = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    return $proto . '://' . $_SERVER['HTTP_HOST'] . strtok($_SERVER['REQUEST_URI'], '?');
}

function next_url($action, $call_sid) {
    return base_url() . '?action=' . urlencode($action) . '&sid=' . urlencode($call_sid);
}

// Play an ElevenLabs MP3 prompt and gather speech response via Deepgram
function twiml_gather($prompt_mp3, $next_action, $call_sid, $timeout = 5, $hints = '') {
    $action_url = next_url($next_action, $call_sid);
    $hint_attr  = $hints ? ' hints="' . htmlspecialchars($hints) . '"' : '';
    echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
    echo '<Response>' . "\n";
    echo '  <Gather input="speech dtmf" action="' . htmlspecialchars($action_url) . '" method="POST"'
        . ' speechTimeout="3"'
        . ' actionOnEmptyResult="true"'
        . ' speechModel="nova-2"'
        . ' profanityFilter="false"'
        . ' timeout="' . $timeout . '"'
        . $hint_attr . '>' . "\n";
    echo '    <Play>' . PROMPT_BASE . htmlspecialchars($prompt_mp3) . '</Play>' . "\n";
    echo '  </Gather>' . "\n";
    // If no input gathered, redirect to same step
    echo '  <Redirect method="POST">' . htmlspecialchars($action_url) . '</Redirect>' . "\n";
    echo '</Response>' . "\n";
    exit;
}

// Play prompt with no gather (final message)
function twiml_play($prompt_mp3) {
    echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
    echo '<Response>' . "\n";
    echo '  <Play>' . PROMPT_BASE . htmlspecialchars($prompt_mp3) . '</Play>' . "\n";
    echo '  <Hangup/>' . "\n";
    echo '</Response>' . "\n";
    exit;
}

function twiml_say($text) {
    echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
    echo '<Response>' . "\n";
    echo '  <Say voice="alice">' . htmlspecialchars($text) . '</Say>' . "\n";
    echo '  <Hangup/>' . "\n";
    echo '</Response>' . "\n";
    exit;
}

function twiml_transfer($number) {
    echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
    echo '<Response>' . "\n";
    echo '  <Dial>' . htmlspecialchars($number) . '</Dial>' . "\n";
    echo '</Response>' . "\n";
    exit;
}

function twiml_redirect($action, $call_sid) {
    echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
    echo '<Response>' . "\n";
    echo '  <Redirect method="POST">' . htmlspecialchars(next_url($action, $call_sid)) . '</Redirect>' . "\n";
    echo '</Response>' . "\n";
    exit;
}

function twiml_hangup() {
    echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
    echo '<Response><Hangup/></Response>' . "\n";
    exit;
}

// ─── RC SMS (via RingCentral) ─────────────────────────────────────────────────
function rc_token() {
    $cache = '/tmp/rc_tok_w2g.json';
    if (file_exists($cache)) {
        $t = json_decode(file_get_contents($cache), true);
        if ($t && ($t['expires_at'] ?? 0) > time() + 60) return $t['access_token'];
    }
    $ch = curl_init(RC_SERVER . '/restapi/oauth/token');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => 'grant_type=client_credentials',
        CURLOPT_HTTPHEADER     => [
            'Content-Type: application/x-www-form-urlencoded',
            'Authorization: Basic ' . base64_encode(RC_CLIENT_ID . ':' . RC_CLIENT_SECRET),
        ],
    ]);
    $d = json_decode(curl_exec($ch), true);
    curl_close($ch);
    if (empty($d['access_token'])) return null;
    $d['expires_at'] = time() + (int)($d['expires_in'] ?? 3600);
    file_put_contents($cache, json_encode($d));
    return $d['access_token'];
}

function rc_sms($to, $msg) {
    $tok = rc_token();
    if (!$tok) return false;
    $to = preg_replace('/[^0-9+]/', '', $to);
    if ($to[0] !== '+') $to = '+1' . ltrim($to, '1');
    $ch = curl_init(RC_SERVER . '/restapi/v1.0/account/~/extension/~/sms');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => json_encode([
            'from' => ['phoneNumber' => RC_SMS_FROM],
            'to'   => [['phoneNumber' => $to]],
            'text' => $msg,
        ]),
        CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Bearer ' . $tok],
    ]);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_exec($ch);
    curl_close($ch);
    return $code >= 200 && $code < 300;
}

// ─── EMAIL ────────────────────────────────────────────────────────────────────
function send_email($to, $subject, $html) {
    require_once '/home/auto11/public_html/vendor/autoload.php';
    try {
        $mail = new PHPMailer\PHPMailer\PHPMailer(true);
        $mail->isSMTP();
        $mail->Host       = 'smtp.gmail.com';
        $mail->SMTPAuth   = true;
        $mail->Username   = W2G_EMAIL;
        $mail->Password   = $GLOBALS['config']['gmail_app_password'] ?? '';
        $mail->SMTPSecure = 'ssl';
        $mail->Port       = 465;
        $mail->setFrom(W2G_EMAIL, IVR_COMPANY);
        $mail->addAddress($to);
        $mail->isHTML(true);
        $mail->Subject = $subject;
        $mail->Body    = $html;
        $mail->send();
        ivr_log("Email sent to $to");
        return true;
    } catch (Exception $e) {
        ivr_log('Email failed: ' . $e->getMessage());
        return false;
    }
}

// ─── WRITE ORDER TO DB ────────────────────────────────────────────────────────
function write_order(&$sess) {
    $db = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
    if ($db->connect_error) { ivr_log('DB error: ' . $db->connect_error); return false; }

    $acct         = $sess['account']  ?? [];
    $ocode        = $acct['code']     ?? 'W2G';
    $aff_id       = (int)($acct['aff_id'] ?? 0);
    $install_date = date('Y-m-d', strtotime('+1 day'));

    $f = [
        'zip'    => $db->real_escape_string($sess['zip']    ?? ''),
        'year'   => $db->real_escape_string($sess['year']   ?? ''),
        'make'   => $db->real_escape_string(ucwords(strtolower($sess['make']   ?? ''))),
        'model'  => $db->real_escape_string(ucwords(strtolower($sess['model']  ?? ''))),
        'style'  => $db->real_escape_string(ucwords(strtolower($sess['style']  ?? ''))),
        'glass'  => $db->real_escape_string(ucwords(strtolower($sess['glass']  ?? ''))),
        'first'  => $db->real_escape_string(ucwords(strtolower($sess['first']  ?? ''))),
        'last'   => $db->real_escape_string(ucwords(strtolower($sess['last']   ?? ''))),
        'street' => $db->real_escape_string(ucwords(strtolower($sess['street'] ?? ''))),
        'city'   => $db->real_escape_string(ucwords(strtolower($sess['city']   ?? ''))),
        'state'  => $db->real_escape_string(strtoupper($sess['state']  ?? '')),
        'phone'  => $db->real_escape_string($sess['phone']  ?? ''),
        'email'  => $db->real_escape_string(strtolower($sess['email']  ?? '')),
        'po'     => $db->real_escape_string(strtoupper($sess['po']     ?? ($acct['po_prefill'] ?? ''))),
        'unit'   => $db->real_escape_string(strtoupper($sess['unit']   ?? '')),
        'notes'  => $db->real_escape_string($sess['notes']  ?? ''),
        'company'=> $db->real_escape_string($acct['company'] ?? ''),
        'sid'    => $db->real_escape_string('ivr_' . ($sess['call_sid'] ?? '')),
    ];

    $nags_part  = $db->real_escape_string($sess['nags_part']  ?? '');
    $nags_style = $db->real_escape_string($sess['nags_style'] ?? ($sess['style'] ?? ''));

    // Look up productID from NAGS part number
    // nspart stores base part (e.g. FW5460) without suffix (GTY etc)
    $product_id = 0;
    if ($nags_part) {
        // Try exact match on nspart
        $row = $db->query("SELECT ID FROM product WHERE nspart='$nags_part' LIMIT 1");
        if ($row && $row->num_rows > 0) {
            $product_id = (int)$row->fetch_assoc()['ID'];
        }
        // Strip trailing letter suffix to get base part (FW5460GTY → FW5460)
        if (!$product_id) {
            $base_part = preg_replace('/^([A-Z]{1,3}\d+)[A-Z]+$/i', '$1', $nags_part);
            if ($base_part !== $nags_part) {
                $esc_base = $db->real_escape_string($base_part);
                $row2 = $db->query("SELECT ID FROM product WHERE nspart='$esc_base' LIMIT 1");
                if ($row2 && $row2->num_rows > 0) {
                    $product_id = (int)$row2->fetch_assoc()['ID'];
                    ivr_log("productID found via base part: $base_part → $product_id");
                }
            }
        }
        // Try part column as last resort
        if (!$product_id) {
            $row3 = $db->query("SELECT ID FROM product WHERE part='$nags_part' LIMIT 1");
            if ($row3 && $row3->num_rows > 0) {
                $product_id = (int)$row3->fetch_assoc()['ID'];
            }
        }
    }
    ivr_log("productID=$product_id for part=$nags_part");

    // cart
    $db->query("INSERT INTO cart (stamp, subtotal, zip, ip, session, randomKey)
                VALUES (Now(), 0, '{$f['zip']}', '127.0.0.1', '{$f['sid']}', '(ivr)')");
    $cart_id = $db->insert_id;
    if (!$cart_id) { ivr_log('cart insert failed: ' . $db->error); $db->close(); return false; }

    // cartItems — parameters='inst' flags as installation order, use real productID if found
    $db->query("INSERT INTO cartItems (cartID, productID, itemPrice, quantity, parameters, partDetails)
                VALUES ($cart_id, $product_id, 0, 1, 'inst', '{$f['zip']}')");

    // Build comments — vehicle summary + NAGS match + caller notes
    $vehicle_summary = "{$f['year']} {$f['make']} {$f['model']} — $nags_style — {$f['glass']}";
    if ($nags_part) $vehicle_summary .= " (NAGS: $nags_part)";
    $notes_clean = $f['notes'] ? "\nNotes: {$f['notes']}" : '';
    $vehicle_str = $db->real_escape_string("[IVR] $vehicle_summary$notes_clean");

    // checkout
    $db->query("INSERT INTO checkout SET
        cartID=$cart_id,
        s_FirstName='{$f['first']}', s_LastName='{$f['last']}',
        s_Email='{$f['email']}', s_Address='{$f['street']}',
        s_City='{$f['city']}', s_State='{$f['state']}',
        s_Zip='{$f['zip']}', s_Phone='{$f['phone']}',
        s_VIN='', s_Unit='{$f['unit']}', s_PO='{$f['po']}',
        s_Company='{$f['company']}', s_CrossStreet='',
        s_InstallYear='{$f['year']}',
        b_FirstName='{$f['first']}', b_LastName='{$f['last']}',
        b_Address='{$f['street']}', b_City='{$f['city']}',
        b_State='{$f['state']}', b_Zip='{$f['zip']}',
        b_Email='{$f['email']}', b_Phone='{$f['phone']}',
        comments='$vehicle_str', s_InstallDate='$install_date',
        b_SameAsShipping=0, b_Country='USA', s_Country='USA',
        c_num='', c_type='', c_expyear='', c_expmonth='', c_cvv='',
        subtotal=0, shipping=0, total=0");
    $checkout_id = $db->insert_id;

    // orderNums
    $esc_code = $db->real_escape_string($ocode);
    $db->query("INSERT INTO orderNums (stamp, refID, code, num)
                SELECT Now(), 0, '$esc_code',
                IF(MAX(num)+1 > 1, MAX(num)+1, 1)
                FROM orderNums WHERE code='$esc_code'");
    $onum_id = $db->insert_id;
    $orow    = $db->query("SELECT num FROM orderNums WHERE ID=$onum_id")->fetch_assoc();
    $onum    = (int)($orow['num'] ?? 1);
    $codenum = $ocode . '-' . sprintf('%04d', $onum);
    $ckey    = rand(1000, 9999);

    // invoice
    $db->query("INSERT INTO invoice SET
        checkoutID=$checkout_id, cartID=$cart_id,
        affiliateID=$aff_id, orderCode='$esc_code', orderNum=$onum,
        customerKey=$ckey, fulfilled='N',
        purchaseDate=Now(), installDate='$install_date'");
    $invoice_id = $db->insert_id;
    $db->close();

    if (!$invoice_id) { ivr_log('invoice insert failed'); return false; }

    // Write vehicle data to ivr_vehicles (before close)
    $v_year  = $db->real_escape_string($sess['year']    ?? '');
    $v_make  = $db->real_escape_string($sess['make']    ?? '');
    $v_model = $db->real_escape_string($sess['model']   ?? '');
    $v_style = $db->real_escape_string($sess['style']   ?? '');
    $v_glass = $db->real_escape_string($sess['glass']   ?? '');
    $v_acct  = $db->real_escape_string($acct['code']    ?? '');
    $db->query("INSERT INTO ivr_vehicles
        (invoice_id, cart_id, year, make, model, style, glass, zip, account, nags_part, nags_style)
        VALUES ($invoice_id, $cart_id, '$v_year', '$v_make', '$v_model',
                '$v_style', '$v_glass', '{$f['zip']}', '$v_acct',
                '$nags_part', '$nags_style')");

    $db->close();

    $sess['invoice_id']   = $invoice_id;
    $sess['order_num']    = $codenum;
    $sess['customer_key'] = $ckey;
    $sess['install_date'] = $install_date;

    ivr_log("Order created: $codenum invoiceID=$invoice_id");
    return true;
}

// ─── BUILD ORDER EMAIL ────────────────────────────────────────────────────────
function build_order_email(&$sess, $vin_url) {
    $acct    = $sess['account']      ?? [];
    $company = $acct['company']      ?? '';
    $onum    = $sess['order_num']    ?? '';
    $install = $sess['install_date'] ?? 'Tomorrow';

    return "
<html><body style='font-family:Arial,sans-serif;font-size:14px;'>
<h2 style='color:#003366;'>" . IVR_COMPANY . " — IVR Order</h2>
<table cellpadding='6' cellspacing='0' style='width:100%;max-width:620px;border-collapse:collapse;'>
  <tr><td colspan='2' style='background:#003366;color:#fff;padding:10px;font-weight:bold;font-size:16px;'>
    Order # $onum &nbsp;|&nbsp; $company
  </td></tr>
  <tr><td style='color:#666;width:35%;border-bottom:1px solid #eee;'>Install Date</td>
      <td style='border-bottom:1px solid #eee;'>$install <em style='color:#999;'>(default — subject to confirmation)</em></td></tr>
  <tr bgcolor='#f9f9f9'><td style='color:#666;border-bottom:1px solid #eee;'>Vehicle</td>
      <td style='border-bottom:1px solid #eee;'>" . htmlspecialchars(($sess['year'] ?? '') . ' ' . ($sess['make'] ?? '') . ' ' . ($sess['model'] ?? '') . ' ' . ($sess['style'] ?? '')) . "</td></tr>
  <tr><td style='color:#666;border-bottom:1px solid #eee;'>Glass</td>
      <td style='border-bottom:1px solid #eee;'>" . htmlspecialchars($sess['glass'] ?? '') . "</td></tr>
  <tr bgcolor='#f9f9f9'><td style='color:#666;border-bottom:1px solid #eee;'>Customer</td>
      <td style='border-bottom:1px solid #eee;'>" . htmlspecialchars(($sess['first'] ?? '') . ' ' . ($sess['last'] ?? '')) . "</td></tr>
  <tr><td style='color:#666;border-bottom:1px solid #eee;'>Address</td>
      <td style='border-bottom:1px solid #eee;'>" . htmlspecialchars(($sess['street'] ?? '') . ', ' . ($sess['city'] ?? '') . ', ' . ($sess['state'] ?? '') . ' ' . ($sess['zip'] ?? '')) . "</td></tr>
  <tr bgcolor='#f9f9f9'><td style='color:#666;border-bottom:1px solid #eee;'>Phone</td>
      <td style='border-bottom:1px solid #eee;'>" . htmlspecialchars($sess['phone'] ?? '') . "</td></tr>
  <tr><td style='color:#666;border-bottom:1px solid #eee;'>Email</td>
      <td style='border-bottom:1px solid #eee;'>" . htmlspecialchars($sess['email'] ?? '') . "</td></tr>
  <tr bgcolor='#f9f9f9'><td style='color:#666;border-bottom:1px solid #eee;'>PO / RO</td>
      <td style='border-bottom:1px solid #eee;'>" . htmlspecialchars($sess['po'] ?? '') . "</td></tr>
  <tr><td style='color:#666;border-bottom:1px solid #eee;'>Unit #</td>
      <td style='border-bottom:1px solid #eee;'>" . htmlspecialchars($sess['unit'] ?? '') . "</td></tr>
  <tr bgcolor='#f9f9f9'><td style='color:#666;border-bottom:1px solid #eee;'>Notes</td>
      <td style='border-bottom:1px solid #eee;'>" . nl2br(htmlspecialchars($sess['notes'] ?? '')) . "</td></tr>
  <tr><td colspan='2' style='padding:14px 6px;'>
    <strong>VIN Entry Link:</strong><br>
    <a href='$vin_url' style='color:#003366;'>$vin_url</a>
  </td></tr>
  <tr><td colspan='2' style='padding:6px;background:#fff8e1;font-size:12px;color:#888;'>
    Order placed via IVR &nbsp;|&nbsp; Twilio SID: " . htmlspecialchars($sess['call_sid'] ?? '') . "
  </td></tr>
</table>
</body></html>";
}

// ─── MAIN ────────────────────────────────────────────────────────────────────
header('Content-Type: text/xml');
validate_twilio();

// Get Twilio params
$call_sid = $_POST['CallSid']      ?? $_GET['CallSid']      ?? '';
$ani      = $_POST['From']         ?? $_GET['From']         ?? '';
$dnis     = $_POST['To']           ?? $_GET['To']           ?? '';
$speech   = $_POST['SpeechResult'] ?? $_GET['SpeechResult'] ?? '';
$digit    = $_POST['Digits']       ?? $_GET['Digits']       ?? '';
// Deepgram often appends a trailing period — strip it globally
$said     = trim(rtrim(trim($speech ?: $digit), '. '));
$action   = $_GET['action']        ?? 'welcome';
$sid      = $_GET['sid']           ?? $call_sid;

// Normalize DNIS — Twilio passes RC forwarded number
$dnis_clean = '+1' . preg_replace('/[^0-9]/', '', $dnis);
if (strlen($dnis_clean) > 12) $dnis_clean = substr($dnis_clean, 0, 12);

ivr_log("[$sid] action=$action dnis_raw=$dnis dnis_clean=$dnis_clean ani=$ani ForwardedFrom=" . ($_POST["ForwardedFrom"] ?? "none") . " said=" . json_encode($said));

// Load/init session
global $ACCOUNTS, $DEFAULT_ACCOUNT;
$sess = sess_load($sid);
if (empty($sess)) {
    $acct = $ACCOUNTS[$dnis_clean] ?? $DEFAULT_ACCOUNT;
    $sess = [
        'call_sid' => $call_sid,
        'ani'      => $ani,
        'dnis'     => $dnis_clean,
        'account'  => $acct,
    ];
    sess_save($sid, $sess);
}
$acct = $sess['account'] ?? $DEFAULT_ACCOUNT;

// ── Universal key presses ─────────────────────────────────────────────────────
if ($digit === '0') {
    sess_del($sid);
    twiml_transfer(IVR_TRANSFER);
}
if ($digit === '9') {
    // Start over — clear session and restart
    sess_del($sid);
    $acct_new = $ACCOUNTS[$dnis_clean] ?? $DEFAULT_ACCOUNT;
    $sess = ['call_sid' => $call_sid, 'ani' => $ani, 'dnis' => $dnis_clean, 'account' => $acct_new];
    sess_save($sid, $sess);
    twiml_redirect('welcome', $sid);
}

// ─── STEP ROUTER ─────────────────────────────────────────────────────────────
switch ($action) {

    // ── WELCOME + ZIP ────────────────────────────────────────────────────────
    case 'welcome':
        twiml_gather('01_welcome.mp3', 'got_zip', $sid, 7,
            'one two three four five six seven eight nine zero');

    // ── GOT ZIP ──────────────────────────────────────────────────────────────
    case 'got_zip':
        $zip = preg_replace('/[^0-9]/', '', $said);
        if (strlen($zip) !== 5) {
            twiml_gather('02_ask_zip_retry.mp3', 'got_zip', $sid, 7);
        }
        $sess['zip'] = $zip;
        sess_save($sid, $sess);
        twiml_gather('03_ask_year.mp3', 'got_year', $sid, 5,
            'nineteen ninety two thousand twenty twenty-one twenty-two twenty-three twenty-four twenty-five');

    // ── GOT YEAR ─────────────────────────────────────────────────────────────
    case 'got_year':
        // Convert spoken year to digits (e.g. "twenty twenty four" → 2024)
        $year_raw = strtolower(trim($said));
        $year = preg_replace('/[^0-9]/', '', $said);
        // Handle spoken form
        if (strlen($year) !== 4) {
            $spoken = [
                'nineteen ninety' => '1990', 'nineteen ninety-one' => '1991',
                'nineteen ninety-two' => '1992', 'nineteen ninety-three' => '1993',
                'nineteen ninety-four' => '1994', 'nineteen ninety-five' => '1995',
                'nineteen ninety-six' => '1996', 'nineteen ninety-seven' => '1997',
                'nineteen ninety-eight' => '1998', 'nineteen ninety-nine' => '1999',
                'two thousand' => '2000', 'two thousand one' => '2001',
                'two thousand two' => '2002', 'two thousand three' => '2003',
                'two thousand four' => '2004', 'two thousand five' => '2005',
                'two thousand six' => '2006', 'two thousand seven' => '2007',
                'two thousand eight' => '2008', 'two thousand nine' => '2009',
                'two thousand ten' => '2010', 'two thousand eleven' => '2011',
                'two thousand twelve' => '2012', 'two thousand thirteen' => '2013',
                'two thousand fourteen' => '2014', 'two thousand fifteen' => '2015',
                'two thousand sixteen' => '2016', 'two thousand seventeen' => '2017',
                'two thousand eighteen' => '2018', 'two thousand nineteen' => '2019',
                'twenty twenty' => '2020', 'twenty-twenty' => '2020',
                'twenty twenty-one' => '2021', 'twenty twenty one' => '2021',
                'twenty twenty-two' => '2022', 'twenty twenty two' => '2022',
                'twenty twenty-three' => '2023', 'twenty twenty three' => '2023',
                'twenty twenty-four' => '2024', 'twenty twenty four' => '2024',
                'twenty twenty-five' => '2025', 'twenty twenty five' => '2025',
                'twenty twenty-six' => '2026', 'twenty twenty six' => '2026',
            ];
            foreach ($spoken as $phrase => $val) {
                if (strpos($year_raw, $phrase) !== false) { $year = $val; break; }
            }
        }
        if (strlen($year) !== 4 || (int)$year < 1980 || (int)$year > 2030) {
            twiml_gather('04_ask_year_retry.mp3', 'got_year', $sid, 5);
        }
        $sess['year'] = $year;
        sess_save($sid, $sess);
        twiml_gather('05_ask_make.mp3', 'got_make', $sid, 5,
            'Toyota Ford Chevrolet Honda Nissan Dodge GMC Hyundai Kia Subaru Jeep BMW Mercedes Volkswagen Audi Ram Tesla Lexus Acura Mazda Volvo Buick Cadillac Chrysler Infiniti Lincoln Mitsubishi');

    // ── GOT MAKE ─────────────────────────────────────────────────────────────
    case 'got_make':
        $make = ucwords(strtolower(trim($said)));
        if (empty($make)) twiml_gather('06_ask_make_retry.mp3', 'got_make', $sid, 5);
        $sess['make'] = $make;
        sess_save($sid, $sess);
        twiml_gather('07_ask_model.mp3', 'got_model', $sid, 5);

    // ── GOT MODEL ────────────────────────────────────────────────────────────
    case 'got_model':
        $model = ucwords(strtolower(trim($said)));
        if (empty($model)) twiml_gather('08_ask_model_retry.mp3', 'got_model', $sid, 5);
        $sess['model'] = $model;
        sess_save($sid, $sess);
        twiml_gather('09_ask_style.mp3', 'got_style', $sid, 5,
            'sedan SUV truck van pickup coupe hatchback wagon convertible');

    // ── GOT STYLE ────────────────────────────────────────────────────────────
    case 'got_style':
        $style = ucwords(strtolower(trim($said)));
        if (empty($style)) twiml_gather('10_ask_style_retry.mp3', 'got_style', $sid, 5);
        $sess['style'] = $style;
        sess_save($sid, $sess);
        twiml_gather('11_ask_glass.mp3', 'got_glass', $sid, 5,
            'windshield driver side passenger side rear window back window quarter glass');

    // ── GOT GLASS ────────────────────────────────────────────────────────────
    case 'got_glass':
        $glass = ucwords(strtolower(trim($said)));
        if (empty($glass)) twiml_gather('12_glass_retry.mp3', 'got_glass', $sid, 5);
        $sess['glass'] = $glass;
        sess_save($sid, $sess);
        twiml_gather('13_firstname.mp3', 'got_first', $sid, 5);

    // ── GOT FIRST NAME ───────────────────────────────────────────────────────
    case 'got_first':
        $first = ucwords(strtolower(trim($said)));
        if (empty($first)) twiml_gather('14_firstname_retry.mp3', 'got_first', $sid, 5);
        $sess['first'] = $first;
        sess_save($sid, $sess);
        twiml_gather('15_lastname.mp3', 'got_last', $sid, 5);

    // ── GOT LAST NAME ─────────────────────────────────────────────────────────
    case 'got_last':
        $last = ucwords(strtolower(trim($said)));
        if (empty($last)) twiml_gather('16_lastname_retry.mp3', 'got_last', $sid, 5);
        $sess['last'] = $last;
        sess_save($sid, $sess);
        twiml_gather('17_street.mp3', 'got_street', $sid, 7);

    // ── GOT STREET ───────────────────────────────────────────────────────────
    case 'got_street':
        $street = ucwords(strtolower(trim($said)));
        if (empty($street)) twiml_gather('18_street_retry.mp3', 'got_street', $sid, 7);
        $sess['street'] = $street;
        sess_save($sid, $sess);
        twiml_gather('19_city.mp3', 'got_city', $sid, 5);

    // ── GOT CITY ─────────────────────────────────────────────────────────────
    case 'got_city':
        $city = ucwords(strtolower(trim($said)));
        if (empty($city)) twiml_gather('20_city_retry.mp3', 'got_city', $sid, 5);
        $sess['city'] = $city;
        sess_save($sid, $sess);
        twiml_gather('21_state.mp3', 'got_state', $sid, 4,
            'Alabama Alaska Arizona Arkansas California Colorado Connecticut Delaware Florida Georgia Hawaii Idaho Illinois Indiana Iowa Kansas Kentucky Louisiana Maine Maryland Massachusetts Michigan Minnesota Mississippi Missouri Montana Nebraska Nevada New Hampshire New Jersey New Mexico New York North Carolina North Dakota Ohio Oklahoma Oregon Pennsylvania Rhode Island South Carolina South Dakota Tennessee Texas Utah Vermont Virginia Washington West Virginia Wisconsin Wyoming');

    // ── GOT STATE ────────────────────────────────────────────────────────────
    case 'got_state':
        $state_raw = strtolower(trim($said));
        $state_map = [
            'alabama'=>'AL','alaska'=>'AK','arizona'=>'AZ','arkansas'=>'AR',
            'california'=>'CA','cal'=>'CA','cali'=>'CA',
            'colorado'=>'CO','connecticut'=>'CT','delaware'=>'DE',
            'florida'=>'FL','georgia'=>'GA','hawaii'=>'HI','idaho'=>'ID',
            'illinois'=>'IL','indiana'=>'IN','iowa'=>'IA','kansas'=>'KS',
            'kentucky'=>'KY','louisiana'=>'LA','maine'=>'ME','maryland'=>'MD',
            'massachusetts'=>'MA','michigan'=>'MI','minnesota'=>'MN','mississippi'=>'MS',
            'missouri'=>'MO','montana'=>'MT','nebraska'=>'NE','nevada'=>'NV',
            'new hampshire'=>'NH','new jersey'=>'NJ','new mexico'=>'NM','new york'=>'NY',
            'north carolina'=>'NC','north dakota'=>'ND','ohio'=>'OH','oklahoma'=>'OK',
            'oregon'=>'OR','pennsylvania'=>'PA','rhode island'=>'RI','south carolina'=>'SC',
            'south dakota'=>'SD','tennessee'=>'TN','texas'=>'TX','utah'=>'UT',
            'vermont'=>'VT','virginia'=>'VA','washington'=>'WA','west virginia'=>'WV',
            'wisconsin'=>'WI','wyoming'=>'WY',
            // common Deepgram variations
            'the state of california'=>'CA','state of california'=>'CA',
            'the state of texas'=>'TX','state of texas'=>'TX',
            'the state of florida'=>'FL','state of florida'=>'FL',
        ];

        // Skip — move on with empty state
        $skip = (stripos($state_raw, 'skip') !== false || stripos($state_raw, 'pass') !== false);

        // Try full name match first
        $state = '';
        if ($skip) {
            $state = '';
        } elseif (isset($state_map[$state_raw])) {
            $state = $state_map[$state_raw];
        } else {
            // Try partial match — Deepgram sometimes adds filler words
            foreach ($state_map as $name => $abbr) {
                if (strpos($state_raw, $name) !== false) { $state = $abbr; break; }
            }
            // Try 2-letter abbreviation directly
            if (!$state) {
                $upper = strtoupper(preg_replace('/[^a-zA-Z]/', '', $state_raw));
                if (strlen($upper) === 2 && in_array($upper, array_values($state_map))) {
                    $state = $upper;
                }
            }
        }

        // If still nothing and not a skip, retry
        if (!$state && !$skip) {
            twiml_gather('22_state_retry.mp3', 'got_state', $sid, 5,
                'Alabama Alaska Arizona Arkansas California Colorado Connecticut Delaware Florida Georgia Hawaii Idaho Illinois Indiana Iowa Kansas Kentucky Louisiana Maine Maryland Massachusetts Michigan Minnesota Mississippi Missouri Montana Nebraska Nevada New Hampshire New Jersey New Mexico New York North Carolina North Dakota Ohio Oklahoma Oregon Pennsylvania Rhode Island South Carolina South Dakota Tennessee Texas Utah Vermont Virginia Washington West Virginia Wisconsin Wyoming skip');
        }

        $sess['state'] = $state;
        sess_save($sid, $sess);
        twiml_gather('23_telephone.mp3', 'got_phone', $sid, 8,
            'zero one two three four five six seven eight nine');

    // ── GOT PHONE ────────────────────────────────────────────────────────────
    case 'got_phone':
        $phone = preg_replace('/[^0-9]/', '', $said);
        if (strlen($phone) === 11 && $phone[0] === '1') $phone = substr($phone, 1);
        // Fallback to ANI if speech fails
        if (strlen($phone) < 10) {
            $ani_digits = preg_replace('/[^0-9]/', '', $sess['ani'] ?? '');
            if (strlen($ani_digits) === 11 && $ani_digits[0] === '1') $ani_digits = substr($ani_digits, 1);
            if (strlen($ani_digits) === 10) $phone = $ani_digits;
        }
        if (strlen($phone) < 10) twiml_gather('24_telephone_retry.mp3', 'got_phone', $sid, 8);
        $sess['phone'] = $phone;
        sess_save($sid, $sess);
        twiml_gather('25_email.mp3', 'got_email', $sid, 10);

    // ── GOT EMAIL ────────────────────────────────────────────────────────────
    case 'got_email':
        $email = strtolower(trim($said));
        // Normalize common speech-to-text patterns
        $email = str_ireplace(
            [' at ', ' dot com', ' dot net', ' dot org', ' dot ', ' underscore ', ' dash ', ' hyphen '],
            ['@',    '.com',     '.net',     '.org',     '.',     '_',            '-',      '-'],
            $email
        );
        $email = preg_replace('/\s+/', '', $email);
        if (empty($email) || strpos($email, '@') === false) {
            twiml_gather('26_email_retry.mp3', 'got_email', $sid, 10);
        }
        $sess['email'] = $email;
        sess_save($sid, $sess);
        // Route to PO or Unit based on account
        if (!empty($acct['ask_po'])) {
            twiml_gather('27_po-ro.mp3', 'got_po', $sid, 6);
        } elseif (!empty($acct['ask_unit'])) {
            twiml_gather('29_unit.mp3', 'got_unit', $sid, 5);
        } else {
            twiml_redirect('play_closing', $sid);
        }

    // ── GOT PO ───────────────────────────────────────────────────────────────
    case 'got_po':
        $po = strtoupper(trim($said));
        $skip_po = (stripos($po, 'SKIP') !== false || stripos($po, 'PASS') !== false || stripos($po, 'NONE') !== false);
        if ($skip_po) $po = '';
        // Accept prefill if nothing said (Lincare)
        if (empty($po) && !$skip_po && !empty($acct['po_prefill'])) $po = $acct['po_prefill'];
        if (empty($po) && !$skip_po) twiml_gather('28_po-ro_retry.mp3', 'got_po', $sid, 6);
        $sess['po'] = $po;
        sess_save($sid, $sess);
        if (!empty($acct['ask_unit'])) {
            twiml_gather('29_unit.mp3', 'got_unit', $sid, 5);
        } else {
            twiml_redirect('play_closing', $sid);
        }

    // ── GOT UNIT ─────────────────────────────────────────────────────────────
    case 'got_unit':
        $unit = strtoupper(trim($said));
        $skip_unit = (stripos($unit, 'SKIP') !== false || stripos($unit, 'PASS') !== false || stripos($unit, 'NONE') !== false);
        if ($skip_unit) $unit = '';
        if (empty($unit) && !$skip_unit) twiml_gather('30_unit_retry.mp3', 'got_unit', $sid, 5);
        $sess['unit'] = $unit;
        sess_save($sid, $sess);
        twiml_redirect('play_closing', $sid);

    // ── CLOSING STATEMENT (no gather) ────────────────────────────────────────
    case 'play_closing':
        echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
        echo '<Response>' . "\n";
        echo '  <Play>' . PROMPT_BASE . '31_finalmesage.mp3</Play>' . "\n";
        echo '  <Redirect method="POST">' . htmlspecialchars(next_url('ask_notes', $sid)) . '</Redirect>' . "\n";
        echo '</Response>' . "\n";
        exit;

    // ── NOTES PROMPT ─────────────────────────────────────────────────────────
    case 'ask_notes':
        twiml_gather('32_notes_prompt.mp3', 'got_notes', $sid, 4);

    // ── GOT NOTES → PROCESS ORDER ────────────────────────────────────────────
    case 'got_notes':
        $notes = trim($said);
        if (strtolower($notes) === 'done' || strtolower($notes) === 'no') $notes = '';
        $sess['notes'] = $notes;
        sess_save($sid, $sess);
        // Redirect to process_order — this runs the NAGS lookup and DB write
        twiml_redirect('process_order', $sid);

    // ── PROCESS ORDER (no audio — runs NAGS + DB + email/SMS) ────────────────
    case 'process_order':
        // NAGS part lookup
        $nags = lookup_nags(
            $sess['year']  ?? '',
            $sess['make']  ?? '',
            $sess['model'] ?? '',
            $sess['style'] ?? '',
            $sess['glass'] ?? 'windshield',
            $sess['zip']   ?? '90001'
        );
        if (!empty($nags['part'])) {
            $sess['nags_part']  = $nags['part'];
            $sess['nags_style'] = $nags['style'];
            ivr_log("[$sid] NAGS part={$nags['part']} style={$nags['style']} score={$nags['score']}");
        } else {
            $sess['nags_part']  = '';
            $sess['nags_style'] = $sess['style'] ?? '';
            ivr_log("[$sid] NAGS lookup returned no part — will write productID=0");
        }

        // Write order to DB
        $ok = write_order($sess);
        sess_save($sid, $sess);

        if (!$ok) {
            ivr_log("[$sid] DB write failed");
            twiml_transfer(IVR_TRANSFER);
        }

        $invoice_id = $sess['invoice_id']   ?? 0;
        $order_num  = $sess['order_num']    ?? '';
        $ckey       = $sess['customer_key'] ?? '';
        $email_addr = $sess['email']        ?? '';
        $caller_num = $sess['ani']          ?? '';

        $vin_url  = VIN_LINK_BASE . '?order=' . $invoice_id . '&key=' . $ckey;
        $email_html = build_order_email($sess, $vin_url);
        $subject    = "IVR Order $order_num — " . ($acct['company'] ?? '') .
                      ' — ' . ($sess['year'] ?? '') . ' ' . ($sess['make'] ?? '') .
                      ' ' . ($sess['model'] ?? '');

        // Email team
        send_email(W2G_EMAIL, $subject, $email_html);

        // Email customer
        if ($email_addr) {
            $cust_html = "
<html><body style='font-family:Arial,sans-serif;font-size:14px;'>
<h2 style='color:#003366;'>Your Order is Confirmed — " . IVR_COMPANY . "</h2>
<p>Thank you. Here is your order summary:</p>
<table cellpadding='6' cellspacing='0' style='width:100%;max-width:500px;border-collapse:collapse;'>
  <tr><td style='color:#666;border-bottom:1px solid #eee;'>Order #</td>
      <td style='border-bottom:1px solid #eee;'><strong>$order_num</strong></td></tr>
  <tr bgcolor='#f9f9f9'><td style='color:#666;border-bottom:1px solid #eee;'>Vehicle</td>
      <td style='border-bottom:1px solid #eee;'>" . htmlspecialchars(($sess['year'] ?? '') . ' ' . ($sess['make'] ?? '') . ' ' . ($sess['model'] ?? '')) . "</td></tr>
  <tr><td style='color:#666;border-bottom:1px solid #eee;'>Glass</td>
      <td style='border-bottom:1px solid #eee;'>" . htmlspecialchars($sess['glass'] ?? '') . "</td></tr>
  <tr bgcolor='#f9f9f9'><td style='color:#666;border-bottom:1px solid #eee;'>Install Date</td>
      <td style='border-bottom:1px solid #eee;'>" . htmlspecialchars($sess['install_date'] ?? '') . " (we will confirm)</td></tr>
</table>
<p style='margin-top:20px;'>Please tap the link below to enter your VIN:<br>
<a href='$vin_url' style='color:#003366;font-weight:bold;'>Enter VIN →</a></p>
<p style='color:#999;font-size:12px;'>If there is any issue we will contact you directly.<br>
" . IVR_COMPANY . " · 877-807-1905</p>
</body></html>";
            send_email($email_addr, "Your Order $order_num — " . IVR_COMPANY, $cust_html);
        }

        // Send SMS via RingCentral using caller's ANI
$caller_num = $sess['ani'] ?? '';
if ($caller_num) {
    $sms_msg = IVR_COMPANY . ": Order $order_num placed. Enter your VIN here: $vin_url";
    rc_sms($caller_num, $sms_msg);
    ivr_log("[$sid] RC SMS sent to $caller_num");
}

sess_del($sid);
// Signoff already played — just hang up
twiml_hangup();

    // ── SIGN-OFF ─────────────────────────────────────────────────────────────
    case 'got_signoff':
        twiml_play('33_signoff.mp3');

    default:
        twiml_transfer(IVR_TRANSFER);
}
