
­­­­­­­­­­­­­­­­­­
<!DOCTYPE html>
<html>
<?php
declare(strict_types=1);
require __DIR__ . '/BaseController.php';

class LeadsController extends BaseController
{
  public function index(): void
{
  $u = require_login($this->pdo, $this->config);

  // Load CC agents only for CC supervisor/admin (for bulk assignment dropdown)
  $agents = [];
  if (has_role($u, ['CC_SUP','ADMIN'])) {
    $st = $this->pdo->prepare("
      SELECT u.id, u.name, u.mobile
      FROM users u
      JOIN roles r ON r.id = u.role_id
      WHERE r.code = 'CC_AGENT'
        AND u.is_active = 1
      ORDER BY u.name
    ");
    $st->execute();
    $agents = $st->fetchAll();
  }

  // Server-side DataTables will fetch rows from leads/datatables
  $this->render('leads/index.php', [
    'u' => $u,
    'agents' => $agents
  ]);
}

  public function create(): void
  {
    $u = require_login($this->pdo, $this->config);
    if (!has_role($u, ['ADMIN','MARKETING','CC_SUP'])) {
      http_response_code(403); echo "Forbidden"; exit;
    }

    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
      csrf_check();

      $country   = trim($_POST['country_code'] ?? ($this->config['default_country_code'] ?? '+966'));
      $mobileRaw = trim($_POST['mobile'] ?? '');
      $mobile    = normalize_mobile($mobileRaw);

      if ($mobile === '') {
        flash_set('danger', 'Mobile is required');
        redirect(base_url($this->config, '/index.php?r=leads/create'));
      }

      $name     = trim($_POST['full_name'] ?? '');
      $city     = trim($_POST['city'] ?? '');
      $source   = trim($_POST['source'] ?? '');
      $campaign = trim($_POST['campaign'] ?? '');
      $vehicle = trim($_POST['vehicle_of_interest'] ?? '');
$modelYear = (int)($_POST['model_year'] ?? 0);
if ($modelYear <= 0) $modelYear = null;

$salary = trim($_POST['salary'] ?? '');
$salary = ($salary === '' ? null : (float)$salary);

$obligation = trim($_POST['obligation'] ?? 'unknown');
if (!in_array($obligation, ['yes','no','unknown'], true)) $obligation = 'unknown';

$salaryRange = trim($_POST['salary_range'] ?? '');

$obAmount = trim($_POST['obligation_amount'] ?? '');
$obAmount = ($obAmount === '' ? null : (float)$obAmount);

$prefTime = trim($_POST['pref_time'] ?? '');
$purchaseTime = trim($_POST['purchase_time'] ?? '');

      $lead_city = trim($_POST['lead_city'] ?? $city);

      $this->pdo->beginTransaction();
      try {
        // find or create contact
        $st = $this->pdo->prepare("SELECT * FROM contacts WHERE country_code=? AND mobile=?");
        $st->execute([$country, $mobile]);
        $contact = $st->fetch();

        $createdContact = false;
        if (!$contact) {
          $st = $this->pdo->prepare("INSERT INTO contacts(country_code, mobile, full_name, city, created_at) VALUES(?,?,?,?,?)");
          $st->execute([$country, $mobile, $name ?: null, $city ?: null, now()]);
          $contactId = (int)$this->pdo->lastInsertId();
          $createdContact = true;
        } else {
          $contactId = (int)$contact['id'];
        }


// create lead
$st = $this->pdo->prepare("
  INSERT INTO leads(
    contact_id,
    source,
    campaign,
    vehicle_of_interest,
    model_year,
    salary,
    obligation,
    salary_range,
    obligation_amount,
    pref_time,
    purchase_time,
    lead_city,
    status,
    created_by_user_id,
    created_at
  ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?, 'new', ?, ?)
");

$st->execute([
  $contactId,
  $source ?: null,
  $campaign ?: null,
  $vehicle ?: null,
  $modelYear,
  $salary,
  $obligation,
  $salaryRange ?: null,
  $obAmount,
  $prefTime ?: null,
  $purchaseTime ?: null,
  $lead_city ?: null,
  (int)$u['id'],
  now()
]);

$leadId = (int)$this->pdo->lastInsertId();

    //    $st->execute([$contactId, $source ?: null, $campaign ?: null, $lead_city ?: null, $u['id'], now()]);
        $leadId = (int)$this->pdo->lastInsertId();

        $this->log('contact', $contactId, $createdContact ? 'CONTACT_CREATED' : 'CONTACT_REUSED', $u['id'], ['mobile'=>$mobile]);
        $this->log(
  'lead',
  $leadId,
  'LEAD_CREATED',
  $u['id'],
  [
    'contact_id' => $contactId,
    'source' => $source,
    'campaign' => $campaign,
    'vehicle' => $vehicle,
    'model_year' => $modelYear
  ]
);

        $this->pdo->commit();
        flash_set('success', 'Lead created');
        redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
      } catch (Throwable $e) {
        $this->pdo->rollBack();
        flash_set('danger', 'Error: ' . $e->getMessage());
      }
    }

    $this->render('leads/create.php', ['u' => $u]);
  }
  

public function update_info(): void
{
  $u = require_login($this->pdo, $this->config);
  require_post(); csrf_check();

  $leadId = (int)($_POST['lead_id'] ?? 0);

  $st = $this->pdo->prepare("SELECT * FROM leads WHERE id=?");
  $st->execute([$leadId]);
  $lead = $st->fetch();
  
  if (!empty($lead['converted_opportunity_id']) || ($lead['qualification'] ?? '') === 'qualified') {
  flash_set('danger', 'Lead is locked after qualification.');
  redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
}
  
  if (!$lead) { http_response_code(404); echo "Lead not found"; exit; }

  // Only CC agent assigned to this lead (or CC_SUP/Admin) can edit
  if (!(
    (has_role($u, ['CC_AGENT']) && (int)$lead['assigned_to_user_id'] === (int)$u['id'])
    || has_role($u, ['CC_SUP','ADMIN'])
  )) {
    http_response_code(403); echo "Forbidden"; exit;
  }

  // Optional lock: only allow update after successful contact
  if (has_role($u, ['CC_AGENT']) && empty($lead['first_success_contact_at'])) {
    flash_set('danger', 'Locked until successful contact');
    redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
  }

  // Read new values
  $vehicle = trim($_POST['vehicle_of_interest'] ?? '');
  $modelYear = (int)($_POST['model_year'] ?? 0);
  if ($modelYear <= 0) $modelYear = null;

  $salary = trim($_POST['salary'] ?? '');
  $salary = ($salary === '' ? null : (float)$salary);

  $salaryRange = trim($_POST['salary_range'] ?? '');

  $obligation = trim($_POST['obligation'] ?? 'unknown');
  if (!in_array($obligation, ['yes','no','unknown'], true)) $obligation = 'unknown';

  $obAmount = trim($_POST['obligation_amount'] ?? '');
  $obAmount = ($obAmount === '' ? null : (float)$obAmount);

  $prefTime = trim($_POST['pref_time'] ?? '');
  $purchaseTime = trim($_POST['purchase_time'] ?? '');

  // Build new values array (store nulls cleanly)
  $new = [
    'vehicle_of_interest' => ($vehicle === '' ? null : $vehicle),
    'model_year' => $modelYear,
    'salary' => $salary,
    'salary_range' => ($salaryRange === '' ? null : $salaryRange),
    'obligation' => $obligation,
    'obligation_amount' => $obAmount,
    'pref_time' => ($prefTime === '' ? null : $prefTime),
    'purchase_time' => ($purchaseTime === '' ? null : $purchaseTime),
  ];

  // Old values (for logging)
  $old = [
    'vehicle_of_interest' => $lead['vehicle_of_interest'] ?? null,
    'model_year' => $lead['model_year'] ?? null,
    'salary' => $lead['salary'] ?? null,
    'salary_range' => $lead['salary_range'] ?? null,
    'obligation' => $lead['obligation'] ?? null,
    'obligation_amount' => $lead['obligation_amount'] ?? null,
    'pref_time' => $lead['pref_time'] ?? null,
    'purchase_time' => $lead['purchase_time'] ?? null,
  ];

  // Determine changes only
  $changed = [];
  foreach ($new as $k => $v) {
    $o = $old[$k] ?? null;

    // Normalize numeric compare
    if (in_array($k, ['model_year'], true)) {
      $o = ($o === null ? null : (int)$o);
      $v = ($v === null ? null : (int)$v);
    }
    if (in_array($k, ['salary','obligation_amount'], true)) {
      $o = ($o === null || $o === '' ? null : (float)$o);
      $v = ($v === null || $v === '' ? null : (float)$v);
    }

    if ($o !== $v) {
      $changed[$k] = ['old' => $o, 'new' => $v];
    }
  }

  if (!$changed) {
    flash_set('info', 'No changes');
    redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
  }

  // Update DB
  $this->pdo->beginTransaction();
  try {
    $st = $this->pdo->prepare("
      UPDATE leads SET
        vehicle_of_interest=?,
        model_year=?,
        salary=?,
        salary_range=?,
        obligation=?,
        obligation_amount=?,
        pref_time=?,
        purchase_time=?,
        updated_at=?
      WHERE id=?
    ");
    $st->execute([
      $new['vehicle_of_interest'],
      $new['model_year'],
      $new['salary'],
      $new['salary_range'],
      $new['obligation'],
      $new['obligation_amount'],
      $new['pref_time'],
      $new['purchase_time'],
      now(),
      $leadId
    ]);

    // Log old vs new (only changed fields)
    $this->log('lead', $leadId, 'LEAD_INFO_UPDATED', (int)$u['id'], [
      'changed' => $changed,
      'old' => $old,
      'new' => $new
    ]);

    $this->pdo->commit();
    flash_set('success', 'Lead info updated');
  } catch (Throwable $e) {
    $this->pdo->rollBack();
    flash_set('danger', 'Error: ' . $e->getMessage());
  }

  redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
}  
  

  /**
   * DataTables server-side endpoint
   */
  public function datatables(): void
  {
    $u = require_login($this->pdo, $this->config);

    $draw   = (int)($_GET['draw'] ?? 1);
    $start  = max(0, (int)($_GET['start'] ?? 0));
    $length = (int)($_GET['length'] ?? 25);
    if ($length <= 0 || $length > 200) $length = 25;

$sf = $_SESSION['leads_filters'] ?? [];

$q = trim($_GET['q'] ?? ($sf['q'] ?? ''));
$status = trim($_GET['status'] ?? ($sf['status'] ?? ''));
$city = trim($_GET['city'] ?? ($sf['city'] ?? ''));

$createdRange  = trim($_GET['created_range'] ?? ($sf['created_range'] ?? ''));
$assignedRange = trim($_GET['assigned_range'] ?? ($sf['assigned_range'] ?? ''));
$prefTime      = trim($_GET['pref_time'] ?? ($sf['pref_time'] ?? ''));



    $orderCol = (int)($_GET['order'][0]['column'] ?? 0);
    $orderDir = strtolower($_GET['order'][0]['dir'] ?? 'desc') === 'asc' ? 'ASC' : 'DESC';

    // If bulk checkbox exists for CC_SUP/ADMIN, DataTables column indexes shift
    $hasBulk = has_role($u, ['CC_SUP','ADMIN']) ? 1 : 0;

    // Column map (whitelist)
    $map = [
      0 => 'l.id',
      1 => 'l.id',
      2 => 'c.mobile',
      3 => 'c.full_name',
      4 => 'l.source',
      5 => 'l.status',
      6 => 'l.vehicle_of_interest',
      7 => 'l.first_view_at',
    ];

    if ($hasBulk === 1) {
      // index 0 is checkbox (not orderable)
      $map = [
        1 => 'l.id',
        2 => 'c.mobile',
        3 => 'c.full_name',
        4 => 'l.source',
        5 => 'l.status',
        6 => 'l.vehicle_of_interest',
        7 => 'l.first_view_at',
      ];
    }

    $orderBy = $map[$orderCol] ?? 'l.id';

    // Scope
    $where = "1=1";
    $params = [];

    if (has_role($u, ['CC_AGENT'])) {
      $where .= " AND l.assigned_to_user_id = ?";
      $params[] = (int)$u['id'];
    } elseif (has_role($u, ['BR_MGR','BR_AGENT'])) {
      $where .= " AND 1=0";
    }

    // Filters
    if ($q !== '') {
      $where .= " AND (c.mobile LIKE ? OR c.full_name LIKE ? OR l.campaign LIKE ? OR l.source LIKE ?)";
      $like = '%' . $q . '%';
      $params = array_merge($params, [$like,$like,$like,$like]);
    }
    if ($status !== '') {
      $where .= " AND l.status = ?";
      $params[] = $status;
    }
    if ($city !== '') {
      $where .= " AND l.lead_city LIKE ?";
      $params[] = '%' . $city . '%';
    }
    
    
    if ($prefTime !== '') {
  $where .= " AND l.pref_time = ?";
  $params[] = $prefTime;
}


if ($createdRange !== '') {
  if ($createdRange === 'today') {
    $where .= " AND DATE(l.created_at) = CURDATE()";
  } elseif ($createdRange === 'yesterday') {
    $where .= " AND DATE(l.created_at) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)";
  } elseif ($createdRange === 'this_week') {
    // Monday-start week
    $where .= " AND YEARWEEK(l.created_at, 1) = YEARWEEK(CURDATE(), 1)";
  } elseif ($createdRange === 'this_month') {
    $where .= " AND YEAR(l.created_at)=YEAR(CURDATE()) AND MONTH(l.created_at)=MONTH(CURDATE())";
  } elseif ($createdRange === 'prev_month') {
    $where .= " AND YEAR(l.created_at)=YEAR(DATE_SUB(CURDATE(), INTERVAL 1 MONTH))
                AND MONTH(l.created_at)=MONTH(DATE_SUB(CURDATE(), INTERVAL 1 MONTH))";
  }
}

if ($assignedRange !== '') {
  // Only rows that have assigned_at
  $where .= " AND l.assigned_at IS NOT NULL";

  if ($assignedRange === 'today') {
    $where .= " AND DATE(l.assigned_at) = CURDATE()";
  } elseif ($assignedRange === 'yesterday') {
    $where .= " AND DATE(l.assigned_at) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)";
  } elseif ($assignedRange === 'this_week') {
    $where .= " AND YEARWEEK(l.assigned_at, 1) = YEARWEEK(CURDATE(), 1)";
  } elseif ($assignedRange === 'this_month') {
    $where .= " AND YEAR(l.assigned_at)=YEAR(CURDATE()) AND MONTH(l.assigned_at)=MONTH(CURDATE())";
  } elseif ($assignedRange === 'prev_month') {
    $where .= " AND YEAR(l.assigned_at)=YEAR(DATE_SUB(CURDATE(), INTERVAL 1 MONTH))
                AND MONTH(l.assigned_at)=MONTH(DATE_SUB(CURDATE(), INTERVAL 1 MONTH))";
  }
}

    

    // Total records (scoped, without filters)
    $whereTotal = "1=1";
    $paramsTotal = [];
    if (has_role($u, ['CC_AGENT'])) {
      $whereTotal .= " AND l.assigned_to_user_id = ?";
      $paramsTotal[] = (int)$u['id'];
    } elseif (has_role($u, ['BR_MGR','BR_AGENT'])) {
      $whereTotal .= " AND 1=0";
    }

    $st = $this->pdo->prepare("
      SELECT COUNT(*) cnt
      FROM leads l
      JOIN contacts c ON c.id = l.contact_id
      WHERE $whereTotal
    ");
    $st->execute($paramsTotal);
    $recordsTotal = (int)$st->fetchColumn();

    // Filtered records
    $st = $this->pdo->prepare("
      SELECT COUNT(*) cnt
      FROM leads l
      JOIN contacts c ON c.id = l.contact_id
      WHERE $where
    ");
    $st->execute($params);
    $recordsFiltered = (int)$st->fetchColumn();

    // Data page
    $sql = "
    select
    l.id,
  l.source,
  l.status,
  l.first_view_at,
  l.vehicle_of_interest,
  l.model_year,
  c.mobile,
  c.full_name
      FROM leads l
      JOIN contacts c ON c.id = l.contact_id
      WHERE $where
      ORDER BY $orderBy $orderDir
      LIMIT $length OFFSET $start
    ";
    $st = $this->pdo->prepare($sql);
    $st->execute($params);
    $data = $st->fetchAll(PDO::FETCH_ASSOC);

    header('Content-Type: application/json; charset=utf-8');
    echo json_encode([
      'draw' => $draw,
      'recordsTotal' => $recordsTotal,
      'recordsFiltered' => $recordsFiltered,
      'data' => $data,
    ], JSON_UNESCAPED_UNICODE);
    exit;
  }
  


//Save Leads Filter
  
public function save_filters(): void
{
  $u = require_login($this->pdo, $this->config);
  require_post(); csrf_check();

  $_SESSION['leads_filters'] = [
    'q' => trim($_POST['q'] ?? ''),
    'status' => trim($_POST['status'] ?? ''),
    'city' => trim($_POST['city'] ?? ''),
    'created_range' => trim($_POST['created_range'] ?? ''),
    'assigned_range' => trim($_POST['assigned_range'] ?? ''),
    'pref_time' => trim($_POST['pref_time'] ?? ''),
  ];

  header('Content-Type: application/json; charset=utf-8');
  echo json_encode(['ok' => true], JSON_UNESCAPED_UNICODE);
  exit;
}  

//Reset Leads Filter

public function reset_filters(): void
{
  $u = require_login($this->pdo, $this->config);
  require_post(); csrf_check();

  unset($_SESSION['leads_filters']);

  header('Content-Type: application/json; charset=utf-8');
  echo json_encode(['ok' => true], JSON_UNESCAPED_UNICODE);
  exit;
}


  /**
   * Bulk assign leads to a CC Agent
   */
  public function bulk_assign(): void
  {
    $u = require_login($this->pdo, $this->config);
    if (!has_role($u, ['CC_SUP','ADMIN'])) { http_response_code(403); echo "Forbidden"; exit; }
    require_post(); csrf_check();

    $agentId = (int)($_POST['agent_id'] ?? 0);
    $leadIds = $_POST['lead_ids'] ?? [];

    if ($agentId <= 0) {
      flash_set('danger', 'Select an agent');
      redirect(base_url($this->config, '/index.php?r=leads/index'));
    }

    $ids = [];
    foreach ($leadIds as $id) {
      $id = (int)$id;
      if ($id > 0) $ids[] = $id;
    }
    $ids = array_values(array_unique($ids));

    if (!$ids) {
      flash_set('danger', 'Select at least one lead');
      redirect(base_url($this->config, '/index.php?r=leads/index'));
    }

    $placeholders = implode(',', array_fill(0, count($ids), '?'));

    $this->pdo->beginTransaction();
    try {
      // NOTE: placeholders are only for lead IDs (at the end)
      $params = array_merge([$agentId, (int)$u['id'], now(), now()], $ids);

      $st = $this->pdo->prepare("
        UPDATE leads
        SET assigned_to_user_id=?,
            assigned_by_user_id=?,
            assigned_at=?,
            status='assigned',
            updated_at=?
        WHERE id IN ($placeholders)
          AND (converted_opportunity_id IS NULL OR converted_opportunity_id=0)
          AND status IN ('new','assigned','in_progress','contacted')
      ");
      $st->execute($params);
      $affected = $st->rowCount();

      foreach ($ids as $lid) {
        $this->log('lead', (int)$lid, 'ASSIGN_BULK', (int)$u['id'], ['assigned_to' => $agentId]);
      }

      $this->pdo->commit();
      flash_set('success', "Bulk assigned: $affected leads");
    } catch (Throwable $e) {
      $this->pdo->rollBack();
      flash_set('danger', 'Error: ' . $e->getMessage());
    }

    redirect(base_url($this->config, '/index.php?r=leads/index'));
  }

  public function view(): void
  {
    $u = require_login($this->pdo, $this->config);
    $id = (int)($_GET['id'] ?? 0);

    $st = $this->pdo->prepare("
  SELECT l.*, c.country_code, c.mobile, c.full_name, c.city,
         b.name_en AS qualified_branch_name_en,
         b.name_ar AS qualified_branch_name_ar
  FROM leads l
  JOIN contacts c ON c.id=l.contact_id
  LEFT JOIN branches b ON b.id = l.qualified_branch_id
  WHERE l.id=?
");
    $st->execute([$id]);
    $lead = $st->fetch();

    if (!$lead) { http_response_code(404); echo "Lead not found"; exit; }
    if (!can_view_lead($u, $lead)) { http_response_code(403); echo "Forbidden"; exit; }

    // capture first view for assigned call center agent
    if (has_role($u, ['CC_AGENT']) && (int)$lead['assigned_to_user_id'] === (int)$u['id'] && empty($lead['first_view_at'])) {
      $st = $this->pdo->prepare("UPDATE leads
                                 SET first_view_at=?,
                                     status=IF(status='assigned','in_progress',status),
                                     updated_at=?
                                 WHERE id=? AND first_view_at IS NULL");
      $st->execute([now(), now(), $id]);

      $this->log('lead', $id, 'VIEW', $u['id'], ['first_view' => true]);

      // refresh
      $st = $this->pdo->prepare("
  SELECT l.*, c.country_code, c.mobile, c.full_name, c.city,
         b.name_en AS qualified_branch_name_en,
         b.name_ar AS qualified_branch_name_ar
  FROM leads l
  JOIN contacts c ON c.id=l.contact_id
  LEFT JOIN branches b ON b.id = l.qualified_branch_id
  WHERE l.id=?
");
      $st->execute([$id]);
      $lead = $st->fetch();
    } else {
      $this->log('lead', $id, 'VIEW', $u['id'], []);
    }

    // branch list for qualify
    $branches = $this->pdo->query("SELECT id, name_en, name_ar, city, location_url
                                   FROM branches
                                   WHERE is_active=1
                                   ORDER BY id")->fetchAll();

    // call center users list for assignment (FIXED: u.id)
    $agents = $this->pdo->query("
      SELECT u.id, u.name, u.mobile
      FROM users u
      JOIN roles r ON r.id = u.role_id
      WHERE r.code = 'CC_AGENT' AND u.is_active = 1
      ORDER BY u.name
    ")->fetchAll();

    // activity timeline
    $st = $this->pdo->prepare("SELECT a.*, u.name actor_name
                               FROM activity_logs a
                               LEFT JOIN users u ON u.id=a.actor_user_id
                               WHERE a.entity_type='lead' AND a.entity_id=?
                               ORDER BY a.id DESC
                               LIMIT 100");
    $st->execute([$id]);
    $logs = $st->fetchAll();

    $this->render('leads/view.php', [
      'u' => $u,
      'lead' => $lead,
      'branches' => $branches,
      'agents' => $agents,
      'logs' => $logs
    ]);
  }

  public function assign(): void
  {
    $u = require_login($this->pdo, $this->config);
    if (!can_assign_lead($u)) { http_response_code(403); echo "Forbidden"; exit; }
    require_post(); csrf_check();

    $leadId  = (int)($_POST['lead_id'] ?? 0);
    $agentId = (int)($_POST['agent_id'] ?? 0);

    $st = $this->pdo->prepare("SELECT * FROM leads WHERE id=?");
    $st->execute([$leadId]);
    $lead = $st->fetch();
    if (!$lead) { http_response_code(404); echo "Lead not found"; exit; }

    $st = $this->pdo->prepare("UPDATE leads
                               SET assigned_to_user_id=?,
                                   assigned_by_user_id=?,
                                   assigned_at=?,
                                   status='assigned',
                                   updated_at=?
                               WHERE id=?");
    $st->execute([$agentId ?: null, $u['id'], now(), now(), $leadId]);

    $this->log('lead', $leadId, 'ASSIGN', $u['id'], ['assigned_to'=>$agentId]);
    flash_set('success', 'Assigned');
    redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
  }

  public function contact_result(): void
  {
    $u = require_login($this->pdo, $this->config);
    require_post(); csrf_check();

    $leadId  = (int)($_POST['lead_id'] ?? 0);
    $success = (int)($_POST['success'] ?? 0);
    $note    = trim($_POST['note'] ?? '');

    $st = $this->pdo->prepare("SELECT * FROM leads WHERE id=?");
    $st->execute([$leadId]);
    $lead = $st->fetch();
    
    if (!empty($lead['converted_opportunity_id']) || ($lead['qualification'] ?? '') === 'qualified') {
  flash_set('danger', 'Lead is locked after qualification.');
  redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
}

    if (!$lead) { http_response_code(404); echo "Lead not found"; exit; }
    if (!can_update_lead($u, $lead)) { http_response_code(403); echo "Forbidden"; exit; }

    if ($success === 1) {
      $st = $this->pdo->prepare("UPDATE leads
                                 SET first_success_contact_at=COALESCE(first_success_contact_at, ?),
                                     status=IF(status IN ('assigned','in_progress','new'),'contacted',status),
                                     updated_at=?
                                 WHERE id=?");
      $st->execute([now(), now(), $leadId]);
      $this->log('lead', $leadId, 'CONTACT_SUCCESS', $u['id'], ['note'=>$note]);
    } else {
      $this->log('lead', $leadId, 'CONTACT_ATTEMPT', $u['id'], ['note'=>$note]);
    }

    redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
  }

  public function disqualify(): void
  {
    $u = require_login($this->pdo, $this->config);
    require_post(); csrf_check();

    $leadId = (int)($_POST['lead_id'] ?? 0);
    $reason = trim($_POST['reason'] ?? '');

    $st = $this->pdo->prepare("SELECT * FROM leads WHERE id=?");
    $st->execute([$leadId]);
    $lead = $st->fetch();
    
    if (!empty($lead['converted_opportunity_id']) || ($lead['qualification'] ?? '') === 'qualified') {
  flash_set('danger', 'Lead is locked after qualification.');
  redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
}

    if (!$lead) { http_response_code(404); echo "Lead not found"; exit; }
    if (!can_update_lead($u, $lead)) { http_response_code(403); echo "Forbidden"; exit; }

    if (empty($lead['first_success_contact_at'])) {
      flash_set('danger', 'Locked until successful contact');
      redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
    }

    $st = $this->pdo->prepare("UPDATE leads
                               SET qualification='disqualified',
                                   disqualify_reason=?,
                                   status='disqualified',
                                   updated_at=?
                               WHERE id=?");
    $st->execute([$reason ?: null, now(), $leadId]);

    $this->log('lead', $leadId, 'DISQUALIFY', $u['id'], ['reason'=>$reason]);
    flash_set('success', 'Disqualified');
    redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
  }

  public function qualify(): void
  {
    $u = require_login($this->pdo, $this->config);
    require_post(); csrf_check();

    $leadId   = (int)($_POST['lead_id'] ?? 0);
    $branchId = (int)($_POST['branch_id'] ?? 0);
    $note = trim($_POST['qualify_note'] ?? '');

    $st = $this->pdo->prepare("SELECT * FROM leads WHERE id=?");
    $st->execute([$leadId]);
    $lead = $st->fetch();
    
    if (!empty($lead['converted_opportunity_id']) || ($lead['qualification'] ?? '') === 'qualified') {
  flash_set('danger', 'This lead is already qualified and locked.');
  redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
}


if ($note === '') {
  flash_set('danger', 'Notes are required');
  redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
}

    if (!$lead) { http_response_code(404); echo "Lead not found"; exit; }
    if (!can_update_lead($u, $lead)) { http_response_code(403); echo "Forbidden"; exit; }

    if (empty($lead['first_success_contact_at'])) {
      flash_set('danger', 'Locked until successful contact');
      redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
    }

    if ($branchId <= 0) {
      flash_set('danger', 'Branch required');
      redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
    }

    $this->pdo->beginTransaction();
    try {
      // mark qualified
     $st = $this->pdo->prepare("
  UPDATE leads
  SET qualification='qualified',
      qualified_branch_id=?,
      qualified_at=?,
      qualified_by_user_id=?,
      qualify_note=?,
      status='qualified',
      updated_at=?
  WHERE id=?
");
$st->execute([$branchId, now(), (int)$u['id'], ($note ?: null), now(), $leadId]);

      // create opportunity
      $st = $this->pdo->prepare("
  INSERT INTO opportunities(lead_id, contact_id, branch_id, status, stage, created_at)
  VALUES(?,?,?,'open','open_opportunity',?)
");
$st->execute([$leadId, $lead['contact_id'], $branchId, now()]);
      $oppId = (int)$this->pdo->lastInsertId();

      // link back
      $st = $this->pdo->prepare("UPDATE leads SET converted_opportunity_id=? WHERE id=?");
      $st->execute([$oppId, $leadId]);

      $this->log('lead', $leadId, 'QUALIFY', $u['id'], [
  'branch_id'=>$branchId,
  'opportunity_id'=>$oppId,
  'note'=>$note
]);
      $this->log('opportunity', $oppId, 'OPPORTUNITY_CREATED', $u['id'], ['lead_id'=>$leadId]);

      $this->pdo->commit();
      flash_set('success', 'Converted to opportunity');
      redirect(base_url($this->config, '/index.php?r=opps/view&id=' . $oppId));
    } catch (Throwable $e) {
      $this->pdo->rollBack();
      flash_set('danger', 'Error: ' . $e->getMessage());
      redirect(base_url($this->config, '/index.php?r=leads/view&id=' . $leadId));
    }
  }
}
