<?php

require_once '../../core/config.php';
require_once '../../core/session.php';
require_once '../../core/permissions.php';
require_once '../../core/database.php';
require_once '../../services/crm/CrmService.php';
require_once '../../services/crm/CustomerService.php';
require_once '../../services/crm/TimelineAuditService.php';
require_once '../../services/crm/PaymentStatusService.php';
require_once '../../services/crm/OpportunityAccessService.php';
require_once '../../services/crm/OpportunityLifecycleService.php';
require_once '../../services/crm/OpportunityStageHistoryService.php';
require_once '../../services/crm/RestockForecastService.php';
require_once '../../core/notifications.php';

require_login();
require_permission('module.crm');

$sessionUser = current_user();
$currentUser = !empty($sessionUser['name']) ? $sessionUser['name'] : (!empty($sessionUser['email']) ? $sessionUser['email'] : 'Sistema');

$pdo = db();
$customerService = new CustomerService($pdo);
$timelineAudit = new TimelineAuditService($pdo);

$id = isset($_POST['id']) ? (int) $_POST['id'] : 0;

if ($id <= 0) die('ID inválido.');

$stmt = $pdo->prepare("SELECT * FROM crm_opportunities WHERE id = ? AND deleted_at IS NULL LIMIT 1");
$stmt->execute(array($id));
$old = $stmt->fetch();

if (!$old) die('Oportunidad no encontrada.');
OpportunityAccessService::assertCanManage($old, $sessionUser ?: array(), 'editar');
if (!empty($old['archived_at'])) die('La oportunidad está archivada. Reábrela antes de editarla.');

$customerId = isset($_POST['customer_id']) ? (int) $_POST['customer_id'] : 0;
$customer = $customerService->findActiveById($customerId);

$title = isset($_POST['title']) ? trim($_POST['title']) : '';
$stage = isset($_POST['stage']) ? trim($_POST['stage']) : '';
$expectedValue = isset($_POST['expected_value']) ? (float) $_POST['expected_value'] : 0;
$probability = isset($_POST['probability']) ? (int) $_POST['probability'] : 20;
$ownerName = isset($_POST['owner_name']) ? trim($_POST['owner_name']) : '';
$ownerUserId = isset($_POST['owner_user_id']) && $_POST['owner_user_id'] !== '' ? (int) $_POST['owner_user_id'] : null; // AGREGADO
$source = isset($_POST['source']) ? trim($_POST['source']) : '';
$competitor = isset($_POST['competitor']) ? trim($_POST['competitor']) : '';
$expectedCloseDate = isset($_POST['expected_close_date']) && $_POST['expected_close_date'] !== '' ? $_POST['expected_close_date'] : null;
$nextAction = isset($_POST['next_action']) ? trim($_POST['next_action']) : '';
$nextActionDate = isset($_POST['next_action_date']) && $_POST['next_action_date'] !== '' ? $_POST['next_action_date'] : null;
$notes = isset($_POST['notes']) ? trim($_POST['notes']) : '';
$paymentStatus = isset($_POST['payment_status']) ? trim($_POST['payment_status']) : 'no_facturado';
$paymentDueDate = isset($_POST['payment_due_date']) && $_POST['payment_due_date'] !== '' ? $_POST['payment_due_date'] : null;
$paymentPaidDate = isset($_POST['payment_paid_date']) && $_POST['payment_paid_date'] !== '' ? $_POST['payment_paid_date'] : null;

$errors = array();

if (!$customer) $errors['customer_id'] = 'Debe seleccionar un cliente válido.';
if ($title === '') $errors['title'] = 'Debe ingresar un título de oportunidad.';
$allowedStages = array('nuevo', 'contactado', 'cotizando', 'negociacion', 'ganada', 'perdida', 'facturada');
if ($stage === '' || !in_array($stage, $allowedStages, true)) $errors['stage'] = 'Debe seleccionar una etapa válida.';
if (($sessionUser['role'] ?? '') === 'comercial' && $ownerUserId !== null && $ownerUserId !== (int)($sessionUser['id'] ?? 0)) $errors['owner_user_id'] = 'No puedes reasignar la oportunidad a otro responsable.';
if (($old['stage'] ?? '') === 'facturada' && $stage !== 'facturada') $errors['stage'] = 'Una oportunidad facturada no puede retroceder desde el formulario. Usa una reversión administrativa después de anular el DTE.';
if ($stage === 'facturada' && ($old['stage'] ?? '') !== 'facturada') {
    try {
        $lifecycleValidation = new OpportunityLifecycleService($pdo);
        if (!$lifecycleValidation->hasValidIssuedDocument($old)) $errors['stage'] = 'No puedes marcarla como facturada sin un DTE emitido y vigente.';
    } catch (Throwable $e) {
        $errors['stage'] = 'No fue posible validar el DTE asociado.';
    }
}
if ($source === '') $errors['source'] = 'Debe seleccionar un origen.';
if ($expectedCloseDate === null) $errors['expected_close_date'] = 'Debe indicar una fecha estimada de cierre.';
if ($nextAction === '') $errors['next_action'] = 'Debe seleccionar una próxima acción.';
if ($nextActionDate === null) $errors['next_action_date'] = 'Debe indicar una fecha para la próxima acción.';

if (!empty($errors)) {
    if (isset($_POST['ajax']) && $_POST['ajax'] === '1') {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'errors' => $errors]);
        exit;
    }
    $_SESSION['form_errors'] = $errors;
    $_SESSION['form_old'] = $_POST;
    header('Location: /modules/crm/opportunity_edit.php?id=' . $id);
    exit;
}

$billingAdjustment = PaymentStatusService::applyFacturadaRules(array(
    'stage' => $stage,
    'old_stage' => $old['stage'] ?? '',
    'payment_status' => $paymentStatus,
    'payment_due_date' => $paymentDueDate,
    'payment_paid_date' => $paymentPaidDate,
    'payment_terms' => $customer['payment_terms'] ?? ($customer['facto_payment_term'] ?? 'contado'),
    'base_date' => date('Y-m-d'),
));
$paymentStatus = $billingAdjustment['payment_status'];
$paymentDueDate = $billingAdjustment['payment_due_date'];
$paymentPaidDate = $billingAdjustment['payment_paid_date'];
$billingChanges = $billingAdjustment['changes'];

$sets = array(
    'customer_id = ?', 'title = ?', 'customer_name = ?', 'customer_tax_id = ?', 'stage = ?', 'payment_status = ?',
    'payment_due_date = ?', 'payment_paid_date = ?', 'expected_value = ?', 'probability = ?', 'owner_name = ?',
    'owner_user_id = ?', 'source = ?', 'competitor = ?', 'expected_close_date = ?', 'next_action = ?', 'next_action_date = ?',
    'notes = ?', 'updated_at = CURRENT_TIMESTAMP'
);
$params = array(
    $customerId, $title, $customer['customer_name'], $customer['customer_tax_id'], $stage, $paymentStatus,
    $paymentDueDate, $paymentPaidDate, $expectedValue, $probability, $ownerName, $ownerUserId, $source,
    $competitor, $expectedCloseDate, $nextAction, $nextActionDate, $notes
);

if (($old['stage'] ?? '') !== $stage) {
    if ($stage === 'ganada') {
        $sets[] = 'commercial_closed_at = COALESCE(commercial_closed_at, NOW())';
        $sets[] = 'closed_at = COALESCE(closed_at, NOW())';
        $sets[] = "closure_outcome = 'won'";
        $sets[] = "closure_reason = COALESCE(NULLIF(closure_reason,''), 'Actualizada a Ganada desde formulario')";
    } elseif ($stage === 'perdida') {
        $sets[] = 'commercial_closed_at = COALESCE(commercial_closed_at, NOW())';
        $sets[] = 'closed_at = COALESCE(closed_at, NOW())';
        $sets[] = "closure_outcome = 'lost'";
        $sets[] = "closure_reason = COALESCE(NULLIF(closure_reason,''), NULLIF(lost_reason,''), 'Actualizada a Perdida desde formulario')";
    } elseif ($stage === 'facturada') {
        $sets[] = 'commercial_closed_at = COALESCE(commercial_closed_at, NOW())';
        $sets[] = 'closed_at = COALESCE(closed_at, NOW())';
        $sets[] = "closure_outcome = 'invoiced'";
        $sets[] = "closure_reason = COALESCE(NULLIF(closure_reason,''), 'DTE emitido y vigente')";
    } elseif (in_array($old['stage'] ?? '', array('ganada','perdida'), true)) {
        $sets[] = 'commercial_closed_at = NULL';
        $sets[] = 'closed_at = NULL';
        $sets[] = 'closed_by_user_id = NULL';
        $sets[] = 'closure_outcome = NULL';
        $sets[] = 'closure_reason = NULL';
        $sets[] = 'closure_note = NULL';
        $sets[] = 'reopened_at = NOW()';
        $sets[] = 'reopened_by_user_id = ?';
        $params[] = (int)($sessionUser['id'] ?? 0) ?: null;
        $sets[] = 'lost_reason = NULL';
    }
}

$params[] = $id;
$stmt = $pdo->prepare('UPDATE crm_opportunities SET ' . implode(', ', $sets) . ' WHERE id = ? AND deleted_at IS NULL AND archived_at IS NULL');
$stmt->execute($params);

if (($old['stage'] ?? '') !== $stage) {
    $actorId = (int)($sessionUser['id'] ?? 0) ?: null;
    OpportunityStageHistoryService::record($pdo, $id, $old['stage'] ?? null, $stage, $actorId, $currentUser, 'form');
    OpportunityStageHistoryService::lifecycle($pdo, $id, 'stage_change', array('stage' => $old['stage'] ?? null), array('stage' => $stage), $actorId, $currentUser, 'form');
}

$newOpportunityForAudit = array(
    'customer_id' => $customerId,
    'customer_name' => $customer['customer_name'],
    'customer_tax_id' => $customer['customer_tax_id'],
    'title' => $title,
    'stage' => $stage,
    'payment_status' => $paymentStatus,
    'payment_due_date' => $paymentDueDate,
    'payment_paid_date' => $paymentPaidDate,
    'expected_value' => $expectedValue,
    'probability' => $probability,
    'owner_name' => $ownerName,
    'owner_user_id' => $ownerUserId,
    'source' => $source,
    'competitor' => $competitor,
    'expected_close_date' => $expectedCloseDate,
    'next_action' => $nextAction,
    'next_action_date' => $nextActionDate,
    'notes' => $notes,
);

$changes = $timelineAudit->buildOpportunityUpdateChanges($old, $newOpportunityForAudit);
if (!empty($billingChanges)) {
    $changes = array_merge($changes, $billingChanges);
}

// Motor predictivo desacoplado: al facturar solo se crea/actualiza un pronostico.
// La oportunidad de reposicion se activa posteriormente desde cron/daily_jobs.php.
if ($stage === 'facturada' && $old['stage'] !== 'facturada') {
    try {
        $restockService = new RestockForecastService($pdo);
        $forecast = $restockService->refreshFromOpportunity($id, $old['facto_document_id'] ?? null, 'opportunity_form');
        if (!empty($forecast['created'])) {
            $changes[] = 'Pronostico de reposicion actualizado para ' . $forecast['projected_restock_date'] . '. Se activara ' . $forecast['activation_date'] . '.';
        } elseif (!empty($forecast['reason'])) {
            $changes[] = 'Pronostico de reposicion no generado: ' . $forecast['reason'];
        }
    } catch (Throwable $e) {
        error_log('Restock forecast opportunity update ' . $id . ': ' . $e->getMessage());
        $changes[] = 'Pronostico de reposicion pendiente de procesamiento diario.';
    }
}

$newActivityHtml = '';
// Registro limpio de cambios reales
if (!empty($changes)) {
    $desc = implode("\n", $changes);
    $timelineAudit->insertActivity(
        $id,
        $customerId,
        $customer['customer_name'],
        'sistema',
        'Oportunidad actualizada',
        $changes,
        $currentUser,
        ''
    );

    // Construir el HTML de la nueva actividad para inyectarlo en vivo
    $newActivityHtml = '
    <div class="crm-timeline-item" style="animation: fadeIn 0.5s ease-in-out;">
        <span class="crm-timeline-dot sistema"></span>
        <div>
            <strong>Oportunidad actualizada</strong>
            <p class="text-secondary text-sm" style="margin-top: 4px;">' . nl2br(htmlspecialchars($desc)) . '</p>
            <span class="text-muted text-sm" style="margin-top: 4px; display: block;">Justo ahora &middot; ' . htmlspecialchars($currentUser) . '</span>
        </div>
    </div>';
}


// ==========================================================================
// NOTIFICACIONES TRANSVERSALES CRM
// ==========================================================================
$opportunityUrl = '/modules/crm/opportunity.php?id=' . $id;
$oldOwnerUserId = !empty($old['owner_user_id']) ? (int)$old['owner_user_id'] : null;
$oldStage = (string)($old['stage'] ?? '');
$oldPaymentStatus = (string)($old['payment_status'] ?? 'no_facturado');

notify_high_value_opportunity_event(
    $id,
    $title,
    $customer['customer_name'],
    (float)$expectedValue,
    $ownerUserId,
    array('dedupe_key' => 'opportunity.high_value:' . $id)
);

if ($ownerUserId && $ownerUserId !== $oldOwnerUserId) {
    notify_crm_user_event(
        'opportunity.assigned',
        $ownerUserId,
        'Oportunidad asignada: ' . $title,
        'Cliente: ' . $customer['customer_name'] . "\nEtapa: " . $stage . ($expectedValue > 0 ? "\nValor esperado: " . number_format($expectedValue, 0, ',', '.') : ''),
        $opportunityUrl,
        'opportunity',
        $id,
        array('dedupe_key' => 'opportunity.assigned:' . $id . ':' . $ownerUserId)
    );
}

if ($stage === 'facturada' && $oldStage !== 'facturada') {
    notify_crm_owner_or_admin_event(
        'opportunity.facturada',
        $ownerUserId,
        'Oportunidad facturada: ' . $title,
        'Cliente: ' . $customer['customer_name'] . "\nCobranza: " . $paymentStatus . ($paymentDueDate ? "\nVencimiento: " . $paymentDueDate : ''),
        $opportunityUrl,
        'opportunity',
        $id,
        array('dedupe_key' => 'opportunity.facturada:' . $id)
    );
}

if ($paymentStatus !== $oldPaymentStatus && in_array($paymentStatus, array('por_cobrar', 'atrasado', 'pagado'), true)) {
    $billingEvent = $paymentStatus === 'pagado' ? 'billing.paid' : ($paymentStatus === 'atrasado' ? 'billing.overdue' : 'billing.por_cobrar');
    $billingTitle = $paymentStatus === 'pagado' ? 'Cobranza pagada' : ($paymentStatus === 'atrasado' ? 'Cobranza atrasada' : 'Cobranza por cobrar');
    notify_crm_owner_or_admin_event(
        $billingEvent,
        $ownerUserId,
        $billingTitle . ': ' . $title,
        'Cliente: ' . $customer['customer_name'] . "\nEstado anterior: " . $oldPaymentStatus . "\nEstado actual: " . $paymentStatus . ($paymentDueDate ? "\nVencimiento: " . $paymentDueDate : '') . ($paymentPaidDate ? "\nFecha de pago: " . $paymentPaidDate : ''),
        $opportunityUrl,
        'opportunity',
        $id,
        array('dedupe_key' => $billingEvent . ':' . $id . ':' . ($paymentDueDate ?: $paymentPaidDate ?: date('Y-m-d')))
    );
}

// ==========================================================================
// INTEGRACION CALENDARIO (INTERNO + GOOGLE)
// ==========================================================================
if ($ownerUserId) {
    require_once '../../services/crm/CrmCalendarService.php';
    try {
        $calendar = new CrmCalendarService($ownerUserId);
        $calendar->syncOpportunity($id, $customer['customer_name'], $title, $_POST);
    } catch (Exception $e) {
        error_log("Error Calendar Update: " . $e->getMessage());
    }
}
if (isset($_POST['ajax']) && $_POST['ajax'] === '1') {
    header('Content-Type: application/json');
    echo json_encode([
        'success' => true,
        'new_activity_html' => $newActivityHtml
    ]);
    exit;
}

header('Location: /modules/crm/opportunity.php?id=' . $id);
exit;
exit;
exit;
