<?php
/**
 * ASISMA CRM - Integraciones externas (Control Empresas y facturación)
 *
 * 1. Control Empresas: crea empresas en producción vía ws_provision.php
 *    (patrón heredado de ASISMA OPS). Se usa al ganar un lead (cliente) y al
 *    dar de alta un franquiciado. Se configura en config_sistema:
 *      - CE_PROVISION_URL      URL del webservice ws_provision.php
 *      - CE_PROVISION_API_KEY  API key del webservice
 *      - CE_PLANTILLA_ID       ID de la empresa plantilla a clonar (clonar_de)
 *    Si falta configuración, la integración se omite y se deja constancia.
 *
 * 2. Facturación del franquiciado: notifica la venta a la API configurada
 *    en empresas_franquiciados (api_facturacion_url + api_key_facturacion).
 *
 * Ambas llamadas deben ejecutarse FUERA de transacciones de BD (son HTTP).
 * Cada método devuelve array('ejecutado' => bool, 'success' => bool, 'detalle' => string).
 */
class IntegracionesHelper {

    /**
     * Crea el cliente en Control Empresas cuando el lead se marca ganado.
     */
    public static function provisionarClienteControlEmpresas($lead) {
        $db  = Database::getInstance();
        $cfg = self::configGrupo($db, array('CE_PROVISION_URL', 'CE_PROVISION_API_KEY', 'CE_PLANTILLA_ID'));

        if (empty($cfg['CE_PROVISION_URL']) || empty($cfg['CE_PROVISION_API_KEY']) || empty($cfg['CE_PLANTILLA_ID'])) {
            return array(
                'ejecutado' => false,
                'success'   => false,
                'detalle'   => 'Integración Control Empresas no configurada (CE_PROVISION_URL / CE_PROVISION_API_KEY / CE_PLANTILLA_ID). Cliente NO creado en producción.'
            );
        }

        // Datos de empresa y contacto del lead
        $empresa  = null;
        if (!empty($lead['empresa_id'])) {
            $empresa = $db->fetchOne("SELECT * FROM empresas WHERE id = :id", array('id' => $lead['empresa_id']));
        }
        $contacto = $db->fetchOne("SELECT * FROM contactos WHERE id = :id", array('id' => $lead['contacto_id']));

        if (!$empresa || empty($empresa['rut'])) {
            return array(
                'ejecutado' => false,
                'success'   => false,
                'detalle'   => 'El lead no tiene empresa con RUT registrado; complete la ficha de empresa antes de provisionar en Control Empresas.'
            );
        }

        $payload = array(
            'action'          => 'crear',
            'api_key'         => $cfg['CE_PROVISION_API_KEY'],
            'clonar_de'       => (int)$cfg['CE_PLANTILLA_ID'],
            'rut'             => $empresa['rut'],
            'nombre'          => $empresa['nombre_fantasia'] ? $empresa['nombre_fantasia'] : $empresa['razon_social'],
            'razon_social'    => $empresa['razon_social'],
            'giro'            => $empresa['giro'] ? $empresa['giro'] : 'SIN GIRO',
            'correo'          => $lead['correo_real'] ? $lead['correo_real'] : ($empresa['email'] ? $empresa['email'] : ''),
            'telefono'        => $lead['telefono_real'],
            'nombre_contacto' => $contacto ? $contacto['nombre'] : '',
            'direccion'       => $empresa['direccion'] ? $empresa['direccion'] : 'SIN DIRECCION'
        );

        $res = self::postForm($cfg['CE_PROVISION_URL'], $payload, $cfg['CE_PROVISION_API_KEY']);

        if ($res['http_code'] >= 200 && $res['http_code'] < 300 && isset($res['data']['success']) && $res['data']['success']) {
            $nuevoId = isset($res['data']['nuevo_id']) ? $res['data']['nuevo_id'] : null;
            return array(
                'ejecutado' => true,
                'success'   => true,
                'detalle'   => 'Cliente creado en Control Empresas' . ($nuevoId ? " (ID producción: {$nuevoId})" : '') . '.',
                'nuevo_id'  => $nuevoId
            );
        }

        $motivo = isset($res['data']['message']) ? $res['data']['message'] : ('HTTP ' . $res['http_code']);
        return array(
            'ejecutado' => true,
            'success'   => false,
            'detalle'   => 'Control Empresas rechazó la creación del cliente: ' . $motivo
        );
    }

    /**
     * Crea la empresa del franquiciado en Control Empresas al darlo de alta en el CRM.
     * Recibe la fila de empresas_franquiciados y devuelve el mismo formato que
     * provisionarClienteControlEmpresas (con nuevo_id si la creación fue exitosa).
     */
    public static function provisionarFranquiciadoControlEmpresas($empresaFranquiciado) {
        $db  = Database::getInstance();
        $cfg = self::configGrupo($db, array('CE_PROVISION_URL', 'CE_PROVISION_API_KEY', 'CE_PLANTILLA_ID'));

        if (empty($cfg['CE_PROVISION_URL']) || empty($cfg['CE_PROVISION_API_KEY']) || empty($cfg['CE_PLANTILLA_ID'])) {
            return array(
                'ejecutado' => false,
                'success'   => false,
                'detalle'   => 'Integración Control Empresas no configurada; el franquiciado NO fue creado en Control Empresas.'
            );
        }

        if (empty($empresaFranquiciado['rut'])) {
            return array(
                'ejecutado' => false,
                'success'   => false,
                'detalle'   => 'El franquiciado no tiene RUT registrado; no se puede crear en Control Empresas.'
            );
        }

        // Datos de facturacion completos: giro, contacto y comuna (el ID es el
        // de la tabla comuna de CE; el nombre va de respaldo por si cambia el ID)
        $comunaNombre = self::nombreComunaCe($db, $empresaFranquiciado);

        $payload = array(
            'action'          => 'crear',
            'api_key'         => $cfg['CE_PROVISION_API_KEY'],
            'clonar_de'       => (int)$cfg['CE_PLANTILLA_ID'],
            'rut'             => $empresaFranquiciado['rut'],
            'nombre'          => $empresaFranquiciado['nombre_fantasia'] ? $empresaFranquiciado['nombre_fantasia'] : $empresaFranquiciado['razon_social'],
            'razon_social'    => $empresaFranquiciado['razon_social'],
            'giro'            => !empty($empresaFranquiciado['giro']) ? $empresaFranquiciado['giro'] : 'SIN GIRO',
            'correo'          => $empresaFranquiciado['email'] ? $empresaFranquiciado['email'] : '',
            'telefono'        => $empresaFranquiciado['telefono'] ? $empresaFranquiciado['telefono'] : '',
            'nombre_contacto' => !empty($empresaFranquiciado['nombre_contacto']) ? $empresaFranquiciado['nombre_contacto'] : '',
            'direccion'       => !empty($empresaFranquiciado['direccion']) ? $empresaFranquiciado['direccion'] : 'SIN DIRECCION',
            'comuna_id'       => !empty($empresaFranquiciado['comuna_id']) ? (int)$empresaFranquiciado['comuna_id'] : 0,
            'comuna'          => $comunaNombre
        );

        $res = self::postForm($cfg['CE_PROVISION_URL'], $payload, $cfg['CE_PROVISION_API_KEY']);

        if ($res['http_code'] >= 200 && $res['http_code'] < 300 && isset($res['data']['success']) && $res['data']['success']) {
            $nuevoId = isset($res['data']['nuevo_id']) ? $res['data']['nuevo_id'] : null;
            return array(
                'ejecutado' => true,
                'success'   => true,
                'detalle'   => 'Empresa del franquiciado creada en Control Empresas' . ($nuevoId ? " (ID: {$nuevoId})" : '') . '.',
                'nuevo_id'  => $nuevoId
            );
        }

        $motivo = isset($res['data']['message']) ? $res['data']['message'] : ('HTTP ' . $res['http_code']);
        return array(
            'ejecutado' => true,
            'success'   => false,
            'detalle'   => 'Control Empresas rechazó la creación del franquiciado: ' . $motivo
        );
    }

    /**
     * Registra al FRANQUICIADO como cliente (auxiliar tipo 1) dentro de la
     * empresa MATRIZ de Control Empresas, con la lista de precios general
     * FRANQUICIADOS. De esa lista (o de la propia que le asignen en CE)
     * salen sus precios de productos en el CRM.
     */
    public static function registrarFranquiciadoComoClienteMatriz($empresaFranquiciado) {
        $db  = Database::getInstance();
        $cfg = self::configGrupo($db, array('CE_PROVISION_URL', 'CE_PROVISION_API_KEY', 'CE_EMPRESA_MATRIZ_ID', 'CE_LISTA_FRANQUICIADOS_ID'));

        if (empty($cfg['CE_PROVISION_URL']) || empty($cfg['CE_PROVISION_API_KEY']) || empty($cfg['CE_EMPRESA_MATRIZ_ID'])) {
            return array(
                'ejecutado' => false,
                'success'   => false,
                'detalle'   => 'La matriz de Control Empresas no está configurada; el franquiciado no quedó como cliente de ASISMA.'
            );
        }
        if (empty($empresaFranquiciado['rut'])) {
            return array('ejecutado' => false, 'success' => false, 'detalle' => 'El franquiciado no tiene RUT; no se puede registrar como cliente de la matriz.');
        }

        $payload = array(
            'action'          => 'crear_cliente',
            'api_key'         => $cfg['CE_PROVISION_API_KEY'],
            'empresa_id'      => (int)$cfg['CE_EMPRESA_MATRIZ_ID'],
            'rut'             => $empresaFranquiciado['rut'],
            'nombre'          => $empresaFranquiciado['nombre_fantasia'] ? $empresaFranquiciado['nombre_fantasia'] : $empresaFranquiciado['razon_social'],
            'razon_social'    => $empresaFranquiciado['razon_social'],
            'giro'            => !empty($empresaFranquiciado['giro']) ? $empresaFranquiciado['giro'] : 'FRANQUICIADO ASISMA',
            'correo'          => $empresaFranquiciado['email'] ? $empresaFranquiciado['email'] : '',
            'telefono'        => $empresaFranquiciado['telefono'] ? $empresaFranquiciado['telefono'] : '',
            'nombre_contacto' => !empty($empresaFranquiciado['nombre_contacto']) ? $empresaFranquiciado['nombre_contacto'] : '',
            'direccion'       => !empty($empresaFranquiciado['direccion']) ? $empresaFranquiciado['direccion'] : 'SIN DIRECCION',
            'comuna_id'       => !empty($empresaFranquiciado['comuna_id']) ? (int)$empresaFranquiciado['comuna_id'] : 0,
            'comuna'          => self::nombreComunaCe($db, $empresaFranquiciado),
            'lista_precio_id' => (int)$cfg['CE_LISTA_FRANQUICIADOS_ID']
        );

        $res = self::postForm($cfg['CE_PROVISION_URL'], $payload, $cfg['CE_PROVISION_API_KEY']);

        if ($res['http_code'] >= 200 && $res['http_code'] < 300 && isset($res['data']['success']) && $res['data']['success']) {
            $clienteId = isset($res['data']['cliente_id']) ? (int)$res['data']['cliente_id'] : null;
            return array(
                'ejecutado'  => true,
                'success'    => true,
                'detalle'    => 'Franquiciado registrado como cliente de la matriz ASISMA en Control Empresas' . ($clienteId ? " (cliente {$clienteId})" : '') . '.',
                'cliente_id' => $clienteId,
                'lista_id'   => (int)$cfg['CE_LISTA_FRANQUICIADOS_ID']
            );
        }

        $motivo = isset($res['data']['message']) ? $res['data']['message'] : ('HTTP ' . $res['http_code']);
        return array('ejecutado' => true, 'success' => false, 'detalle' => 'Control Empresas rechazó el registro como cliente de la matriz: ' . $motivo);
    }

    /**
     * Nombre de la comuna del franquiciado segun el catalogo espejo comunas_ce.
     * Se manda junto al ID como respaldo (CE resuelve por ID y si no, por nombre).
     */
    private static function nombreComunaCe($db, $empresaFranquiciado) {
        if (empty($empresaFranquiciado['comuna_id'])) return '';
        $fila = $db->fetchOne(
            "SELECT nombre FROM comunas_ce WHERE id = :id",
            array(':id' => (int)$empresaFranquiciado['comuna_id'])
        );
        return $fila ? $fila['nombre'] : '';
    }

    /**
     * Descarga el catalogo de comunas de Control Empresas y lo deja en la tabla
     * comunas_ce. Los IDs de comuna que usa el CRM SIEMPRE salen de aca — nunca
     * se escriben a mano, para que calcen con el CE conectado (dev o produccion).
     */
    public static function sincronizarComunasControlEmpresas() {
        $db  = Database::getInstance();
        $cfg = self::configGrupo($db, array('CE_PROVISION_URL', 'CE_PROVISION_API_KEY'));

        if (empty($cfg['CE_PROVISION_URL']) || empty($cfg['CE_PROVISION_API_KEY'])) {
            return array(
                'ejecutado' => false,
                'success'   => false,
                'detalle'   => 'Integración Control Empresas no configurada; no se pueden sincronizar las comunas.'
            );
        }

        $res = self::postForm($cfg['CE_PROVISION_URL'], array(
            'action'  => 'comunas',
            'api_key' => $cfg['CE_PROVISION_API_KEY']
        ), $cfg['CE_PROVISION_API_KEY']);

        if (!($res['http_code'] >= 200 && $res['http_code'] < 300
            && !empty($res['data']['success']) && !empty($res['data']['comunas']))) {
            $motivo = isset($res['data']['message']) ? $res['data']['message'] : ('HTTP ' . $res['http_code']);
            return array('ejecutado' => true, 'success' => false, 'detalle' => 'Control Empresas no entregó las comunas: ' . $motivo);
        }

        $total = 0;
        foreach ($res['data']['comunas'] as $comuna) {
            if (empty($comuna['id']) || !isset($comuna['nombre']) || trim($comuna['nombre']) === '') continue;
            $db->query(
                "INSERT INTO comunas_ce (id, nombre, ciudad) VALUES (:id, :nombre, :ciudad)
                 ON DUPLICATE KEY UPDATE nombre = :nombre_upd, ciudad = :ciudad_upd",
                array(
                    ':id'         => (int)$comuna['id'],
                    ':nombre'     => trim($comuna['nombre']),
                    ':ciudad'     => isset($comuna['ciudad']) ? trim($comuna['ciudad']) : '',
                    ':nombre_upd' => trim($comuna['nombre']),
                    ':ciudad_upd' => isset($comuna['ciudad']) ? trim($comuna['ciudad']) : ''
                )
            );
            $total++;
        }

        return array(
            'ejecutado' => true,
            'success'   => true,
            'detalle'   => "Se sincronizaron {$total} comunas desde Control Empresas.",
            'total'     => $total
        );
    }

    /**
     * ACTUALIZA los datos de facturación del cliente (auxiliar) ya existente
     * en la empresa Control Empresas del franquiciado, con lo que hoy tiene la
     * ficha de la empresa en el CRM: giro, correo, teléfono, dirección y comuna
     * (ID real del catálogo de CE). Usa ws_provision action=actualizar_cliente.
     */
    public static function actualizarClienteEnFranquiciado($lead) {
        $db  = Database::getInstance();
        $cfg = self::configGrupo($db, array('CE_PROVISION_URL', 'CE_PROVISION_API_KEY'));

        if (empty($cfg['CE_PROVISION_URL']) || empty($cfg['CE_PROVISION_API_KEY'])) {
            return array('ejecutado' => false, 'success' => false,
                'detalle' => 'Integración Control Empresas no configurada; los datos del cliente no se actualizaron en el facturador.');
        }
        if (empty($lead['franquiciado_id'])) {
            return array('ejecutado' => false, 'success' => false, 'detalle' => 'Lead sin franquiciado asignado.');
        }

        $franq = $db->fetchOne(
            "SELECT ef.control_empresas_id, ef.nombre_fantasia
             FROM franquiciados f
             INNER JOIN empresas_franquiciados ef ON f.empresa_madre_id = ef.id
             WHERE f.id = :id",
            array('id' => $lead['franquiciado_id'])
        );
        if (!$franq || empty($franq['control_empresas_id'])) {
            return array('ejecutado' => false, 'success' => false, 'detalle' => 'El franquiciado no tiene empresa en Control Empresas.');
        }

        $empresa = !empty($lead['empresa_id'])
            ? $db->fetchOne("SELECT * FROM empresas WHERE id = :id", array('id' => $lead['empresa_id']))
            : null;
        if (!$empresa || empty($empresa['ce_cliente_id'])) {
            return array('ejecutado' => false, 'success' => false, 'detalle' => 'La empresa no está enlazada como cliente en Control Empresas.');
        }

        $contacto = $db->fetchOne("SELECT * FROM contactos WHERE id = :id", array('id' => $lead['contacto_id']));
        $comunaNombre = '';
        if (!empty($empresa['comuna_id'])) {
            $filaComuna = $db->fetchOne("SELECT nombre FROM comunas_ce WHERE id = :id", array(':id' => (int)$empresa['comuna_id']));
            if ($filaComuna) $comunaNombre = $filaComuna['nombre'];
        }

        $payload = array(
            'action'          => 'actualizar_cliente',
            'api_key'         => $cfg['CE_PROVISION_API_KEY'],
            'empresa_id'      => (int)$franq['control_empresas_id'],
            'cliente_id'      => (int)$empresa['ce_cliente_id'],
            'nombre'          => $empresa['nombre_fantasia'] ? $empresa['nombre_fantasia'] : $empresa['razon_social'],
            'razon_social'    => $empresa['razon_social'],
            'giro'            => $empresa['giro'] ? $empresa['giro'] : '',
            'correo'          => $empresa['email'] ? $empresa['email'] : ($lead['correo_real'] ? $lead['correo_real'] : ''),
            'telefono'        => $empresa['telefono'] ? $empresa['telefono'] : $lead['telefono_real'],
            'nombre_contacto' => $contacto ? $contacto['nombre'] : '',
            'direccion'       => $empresa['direccion'] ? $empresa['direccion'] : '',
            'comuna_id'       => !empty($empresa['comuna_id']) ? (int)$empresa['comuna_id'] : 0,
            'comuna'          => $comunaNombre
        );

        $res = self::postForm($cfg['CE_PROVISION_URL'], $payload, $cfg['CE_PROVISION_API_KEY']);
        $exito = $res['http_code'] >= 200 && $res['http_code'] < 300 && isset($res['data']['success']) && $res['data']['success'];

        AuditHelper::log('actualizar_cliente_ce', 'empresas', (int)$empresa['id'], null, array(
            'ce_cliente_id' => (int)$empresa['ce_cliente_id'],
            'ce_empresa_id' => (int)$franq['control_empresas_id'],
            'giro'          => $payload['giro'],
            'direccion'     => $payload['direccion'],
            'comuna_id'     => $payload['comuna_id'],
            'exito'         => $exito
        ));

        if ($exito) {
            return array('ejecutado' => true, 'success' => true,
                'detalle' => 'Datos de facturación del cliente actualizados en el CE de ' . $franq['nombre_fantasia'] . ' (cliente ' . $empresa['ce_cliente_id'] . ').');
        }
        $motivo = isset($res['data']['message']) ? $res['data']['message'] : ('HTTP ' . $res['http_code']);
        return array('ejecutado' => true, 'success' => false, 'detalle' => 'Control Empresas rechazó la actualización del cliente: ' . $motivo);
    }

    /**
     * Registra el cliente ganado como CLIENTE (auxiliar tipo 1) dentro de la
     * empresa Control Empresas del franquiciado, para que este pueda facturarle
     * o generarle documentos de cotización. Usa ws_provision action=crear_cliente.
     * Idempotente: si la empresa del lead ya tiene ce_cliente_id, no repite.
     */
    public static function crearClienteEnFranquiciado($lead) {
        $db  = Database::getInstance();
        $cfg = self::configGrupo($db, array('CE_PROVISION_URL', 'CE_PROVISION_API_KEY'));

        if (empty($cfg['CE_PROVISION_URL']) || empty($cfg['CE_PROVISION_API_KEY'])) {
            return array(
                'ejecutado' => false,
                'success'   => false,
                'detalle'   => 'Integración Control Empresas no configurada; el cliente NO fue registrado en la cartera del franquiciado.'
            );
        }

        if (empty($lead['franquiciado_id'])) {
            return array(
                'ejecutado' => false,
                'success'   => false,
                'detalle'   => 'Lead sin franquiciado asignado; no hay cartera donde registrar el cliente.'
            );
        }

        // Empresa del franquiciado en Control Empresas
        $franq = $db->fetchOne(
            "SELECT ef.control_empresas_id, ef.nombre_fantasia
             FROM franquiciados f
             INNER JOIN empresas_franquiciados ef ON f.empresa_madre_id = ef.id
             WHERE f.id = :id",
            array('id' => $lead['franquiciado_id'])
        );
        if (!$franq || empty($franq['control_empresas_id'])) {
            return array(
                'ejecutado' => false,
                'success'   => false,
                'detalle'   => 'El franquiciado no tiene empresa en Control Empresas; provisiónela desde Franquiciados y reintente.'
            );
        }

        // Datos del cliente (empresa y contacto del lead)
        $empresa = null;
        if (!empty($lead['empresa_id'])) {
            $empresa = $db->fetchOne("SELECT * FROM empresas WHERE id = :id", array('id' => $lead['empresa_id']));
        }
        if (!$empresa || empty($empresa['rut'])) {
            return array(
                'ejecutado' => false,
                'success'   => false,
                'detalle'   => 'El lead no tiene empresa con RUT registrado; complete la ficha antes de registrar el cliente en Control Empresas.'
            );
        }

        if (!empty($empresa['ce_cliente_id'])) {
            return array(
                'ejecutado' => false,
                'success'   => true,
                'detalle'   => 'El cliente ya estaba registrado en la cartera del franquiciado (CE cliente ' . $empresa['ce_cliente_id'] . ').',
                'cliente_id' => $empresa['ce_cliente_id']
            );
        }

        $contacto = $db->fetchOne("SELECT * FROM contactos WHERE id = :id", array('id' => $lead['contacto_id']));

        // Comuna del cliente por su ID real de CE (catalogo espejo comunas_ce)
        $comunaNombre = '';
        if (!empty($empresa['comuna_id'])) {
            $filaComuna = $db->fetchOne("SELECT nombre FROM comunas_ce WHERE id = :id", array(':id' => (int)$empresa['comuna_id']));
            if ($filaComuna) $comunaNombre = $filaComuna['nombre'];
        }

        $payload = array(
            'action'          => 'crear_cliente',
            'api_key'         => $cfg['CE_PROVISION_API_KEY'],
            'empresa_id'      => (int)$franq['control_empresas_id'],
            'rut'             => $empresa['rut'],
            'nombre'          => $empresa['nombre_fantasia'] ? $empresa['nombre_fantasia'] : $empresa['razon_social'],
            'razon_social'    => $empresa['razon_social'],
            'giro'            => $empresa['giro'] ? $empresa['giro'] : 'SIN GIRO',
            'correo'          => $lead['correo_real'] ? $lead['correo_real'] : ($empresa['email'] ? $empresa['email'] : ''),
            'telefono'        => $lead['telefono_real'],
            'nombre_contacto' => $contacto ? $contacto['nombre'] : '',
            'direccion'       => $empresa['direccion'] ? $empresa['direccion'] : 'SIN DIRECCION',
            'comuna_id'       => !empty($empresa['comuna_id']) ? (int)$empresa['comuna_id'] : 0,
            'comuna'          => $comunaNombre
        );

        $res = self::postForm($cfg['CE_PROVISION_URL'], $payload, $cfg['CE_PROVISION_API_KEY']);

        if ($res['http_code'] >= 200 && $res['http_code'] < 300 && isset($res['data']['success']) && $res['data']['success']) {
            $clienteId = isset($res['data']['cliente_id']) ? (int)$res['data']['cliente_id'] : null;
            if ($clienteId) {
                $db->update('empresas', array('ce_cliente_id' => $clienteId), "id = :id", array('id' => $empresa['id']));
            }
            $yaExistia = !empty($res['data']['ya_existia']);
            return array(
                'ejecutado'  => true,
                'success'    => true,
                'detalle'    => 'Cliente registrado en la cartera de ' . $franq['nombre_fantasia'] . ' en Control Empresas'
                              . ($clienteId ? " (cliente {$clienteId})" : '') . ($yaExistia ? ' — ya existía.' : '.'),
                'cliente_id' => $clienteId
            );
        }

        $motivo = isset($res['data']['message']) ? $res['data']['message'] : ('HTTP ' . $res['http_code']);
        return array(
            'ejecutado' => true,
            'success'   => false,
            'detalle'   => 'Control Empresas rechazó el registro del cliente: ' . $motivo
        );
    }

    /**
     * Genera un documento (COTIZACION o FACTURA) en Control Empresas, dentro de
     * la empresa del franquiciado y asociado al cliente del lead. Control Empresas
     * actúa como software facturador: el documento queda guardado allá y el CRM
     * conserva el linkeo (ce_cotizacion_id/numero o ce_factura_id/numero).
     * Si el cliente aún no existe en la cartera del franquiciado, lo crea primero.
     */
    public static function generarDocumentoEnFranquiciado($cotizacionId, $tipoDocumento) {
        $db  = Database::getInstance();
        $cfg = self::configGrupo($db, array('CE_PROVISION_URL', 'CE_PROVISION_API_KEY'));

        $tipoDocumento = strtoupper($tipoDocumento) === 'FACTURA' ? 'FACTURA' : 'COTIZACION';
        $columnaId  = $tipoDocumento === 'FACTURA' ? 'ce_factura_id' : 'ce_cotizacion_id';
        $columnaNum = $tipoDocumento === 'FACTURA' ? 'ce_factura_numero' : 'ce_cotizacion_numero';

        if (empty($cfg['CE_PROVISION_URL']) || empty($cfg['CE_PROVISION_API_KEY'])) {
            return array(
                'ejecutado' => false,
                'success'   => false,
                'detalle'   => "Integración Control Empresas no configurada; $tipoDocumento no generada en el facturador."
            );
        }

        $cotiz = $db->fetchOne("SELECT * FROM cotizaciones WHERE id = :id", array('id' => $cotizacionId));
        if (!$cotiz) {
            return array('ejecutado' => false, 'success' => false, 'detalle' => 'Cotización no encontrada.');
        }

        if (!empty($cotiz[$columnaId])) {
            return array(
                'ejecutado'  => false,
                'success'    => true,
                'detalle'    => "$tipoDocumento ya generada en Control Empresas (N° {$cotiz[$columnaNum]}).",
                'documento_id' => $cotiz[$columnaId],
                'numero'       => $cotiz[$columnaNum]
            );
        }

        $lead = $db->fetchOne("SELECT * FROM leads WHERE id = :id", array('id' => $cotiz['lead_id']));
        if (!$lead || empty($lead['franquiciado_id'])) {
            return array('ejecutado' => false, 'success' => false, 'detalle' => 'El lead de la cotización no tiene franquiciado asignado.');
        }

        $franq = $db->fetchOne(
            "SELECT ef.control_empresas_id, ef.nombre_fantasia
             FROM franquiciados f
             INNER JOIN empresas_franquiciados ef ON f.empresa_madre_id = ef.id
             WHERE f.id = :id",
            array('id' => $lead['franquiciado_id'])
        );
        if (!$franq || empty($franq['control_empresas_id'])) {
            return array(
                'ejecutado' => false,
                'success'   => false,
                'detalle'   => 'El franquiciado no tiene empresa en Control Empresas; provisiónela desde Franquiciados y reintente.'
            );
        }

        // El documento se asocia al cliente en la cartera del franquiciado:
        // si aún no existe, se crea en el mismo flujo.
        $empresaLead = !empty($lead['empresa_id'])
            ? $db->fetchOne("SELECT id, ce_cliente_id FROM empresas WHERE id = :id", array('id' => $lead['empresa_id']))
            : null;
        if (!$empresaLead) {
            return array('ejecutado' => false, 'success' => false, 'detalle' => 'El lead no tiene empresa registrada; complete la ficha antes de generar documentos.');
        }
        if (empty($empresaLead['ce_cliente_id'])) {
            $resCliente = self::crearClienteEnFranquiciado($lead);
            if (!$resCliente['success'] || empty($resCliente['cliente_id'])) {
                return array('ejecutado' => $resCliente['ejecutado'], 'success' => false,
                             'detalle' => "No se pudo generar la $tipoDocumento: " . $resCliente['detalle']);
            }
            $empresaLead['ce_cliente_id'] = $resCliente['cliente_id'];
        }

        // Montos e ítems desde la cotización (precios del CRM son netos)
        $productos = json_decode($cotiz['productos_json'], true);
        if (empty($productos)) {
            return array('ejecutado' => false, 'success' => false, 'detalle' => 'La cotización no tiene productos.');
        }
        $items = array();
        $hayItemServicio = false;
        foreach ($productos as $p) {
            if (isset($p['clase']) && $p['clase'] === 'servicio_plan') {
                // Plan de servicio: se factura el PAGO INICIAL con glosa clara
                // (la mensualidad recurrente se factura aparte, mes a mes)
                $hayItemServicio = true;
                $items[] = array(
                    'nombre'      => $p['plan_nombre'] . ' — ' . $p['servicio_nombre'] . ' (licencia e implementación)',
                    'cantidad'    => 1,
                    'precio_neto' => isset($p['precio_inicial_clp']) ? $p['precio_inicial_clp'] : 0,
                    'total_neto'  => isset($p['precio_inicial_clp']) ? $p['precio_inicial_clp'] : 0
                );
                continue;
            }
            $items[] = array(
                'nombre'      => isset($p['nombre']) ? $p['nombre'] : 'PRODUCTO',
                'cantidad'    => isset($p['cantidad']) ? $p['cantidad'] : 1,
                'precio_neto' => isset($p['precio']) ? $p['precio'] : 0,
                'total_neto'  => isset($p['total']) ? $p['total'] : 0
            );
        }

        $descMonto = 0;
        if ($cotiz['descuento_valor'] > 0) {
            if ($hayItemServicio) {
                // El descuento de servicios va en la moneda del plan (UF/%):
                // se deriva en CLP desde los montos ya calculados de la cotización
                $factorIva = 1 + ((float)$cotiz['impuesto_pct'] / 100);
                $descMonto = max(0, round($cotiz['subtotal'] - ($cotiz['total'] / $factorIva)));
            } else {
                $descMonto = $cotiz['descuento_tipo'] === 'porcentaje'
                    ? $cotiz['subtotal'] * $cotiz['descuento_valor'] / 100
                    : $cotiz['descuento_valor'];
            }
        }
        $neto = $cotiz['subtotal'] - $descMonto;
        $iva  = $cotiz['total'] - $neto;

        $folio = 'COT-' . str_pad($cotiz['id'], 6, '0', STR_PAD_LEFT);
        $payload = array(
            'action'         => 'crear_documento',
            'api_key'        => $cfg['CE_PROVISION_API_KEY'],
            'empresa_id'     => (int)$franq['control_empresas_id'],
            'cliente_id'     => (int)$empresaLead['ce_cliente_id'],
            'tipo_documento' => $tipoDocumento,
            'referencia'     => 'CRM-' . ($tipoDocumento === 'FACTURA' ? 'FACT' : 'COT') . '-' . $cotiz['id'],
            'observacion'    => 'Generada desde ASISMA CRM (' . $folio . ')',
            'porcentaje_iva' => (int)$cotiz['impuesto_pct'],
            'descuento'      => $descMonto,
            'neto'           => $neto,
            'iva'            => $iva,
            'total'          => $cotiz['total'],
            'validez_dias'   => $tipoDocumento === 'COTIZACION' ? max(1, (int)ceil($cotiz['validez_horas'] / 24)) : 0,
            'items'          => json_encode($items, JSON_UNESCAPED_UNICODE)
        );

        $res = self::postForm($cfg['CE_PROVISION_URL'], $payload, $cfg['CE_PROVISION_API_KEY']);

        if ($res['http_code'] >= 200 && $res['http_code'] < 300 && isset($res['data']['success']) && $res['data']['success']) {
            $docId  = isset($res['data']['documento_id']) ? (int)$res['data']['documento_id'] : null;
            $numero = isset($res['data']['numero']) ? $res['data']['numero'] : null;
            if ($docId) {
                $db->update('cotizaciones', array($columnaId => $docId, $columnaNum => $numero),
                            "id = :id", array('id' => $cotiz['id']));
            }
            return array(
                'ejecutado'    => true,
                'success'      => true,
                'detalle'      => "$tipoDocumento N° $numero generada en el facturador de {$franq['nombre_fantasia']} (Control Empresas, documento $docId).",
                'documento_id' => $docId,
                'numero'       => $numero
            );
        }

        $motivo = isset($res['data']['message']) ? $res['data']['message'] : ('HTTP ' . $res['http_code']);
        return array(
            'ejecutado' => true,
            'success'   => false,
            'detalle'   => "Control Empresas rechazó la generación de la $tipoDocumento: " . $motivo
        );
    }

    /**
     * Notifica la venta ganada a la API de facturación del franquiciado.
     */
    public static function notificarFacturacion($lead) {
        $db = Database::getInstance();

        if (empty($lead['franquiciado_id'])) {
            return array('ejecutado' => false, 'success' => false, 'detalle' => 'Lead sin franquiciado asignado; no hay API de facturación que notificar.');
        }

        $franq = $db->fetchOne(
            "SELECT f.id, ef.razon_social, ef.api_facturacion_url, ef.api_key_facturacion
             FROM franquiciados f
             INNER JOIN empresas_franquiciados ef ON f.empresa_madre_id = ef.id
             WHERE f.id = :id",
            array('id' => $lead['franquiciado_id'])
        );

        if (!$franq || empty($franq['api_facturacion_url'])) {
            return array(
                'ejecutado' => false,
                'success'   => false,
                'detalle'   => 'El franquiciado no tiene API de facturación configurada; venta no notificada.'
            );
        }

        // Última cotización relevante para informar el monto
        $cotizacion = $db->fetchOne(
            "SELECT id, total, moneda, estado FROM cotizaciones
             WHERE lead_id = :lid AND activo = 1
             ORDER BY FIELD(estado, 'aceptada', 'vista', 'enviada', 'borrador'), id DESC
             LIMIT 1",
            array('lid' => $lead['id'])
        );

        $empresa = null;
        if (!empty($lead['empresa_id'])) {
            $empresa = $db->fetchOne("SELECT rut, razon_social FROM empresas WHERE id = :id", array('id' => $lead['empresa_id']));
        }

        $payload = array(
            'evento'          => 'lead_ganado',
            'lead_id'         => (int)$lead['id'],
            'franquiciado_id' => (int)$lead['franquiciado_id'],
            'fecha'           => date('Y-m-d H:i:s'),
            'cliente'         => array(
                'rut'          => $empresa ? $empresa['rut'] : null,
                'razon_social' => $empresa ? $empresa['razon_social'] : null,
                'telefono'     => $lead['telefono_real'],
                'correo'       => $lead['correo_real']
            ),
            'cotizacion'      => $cotizacion ? array(
                'id'     => (int)$cotizacion['id'],
                'total'  => (float)$cotizacion['total'],
                'moneda' => $cotizacion['moneda'],
                'estado' => $cotizacion['estado']
            ) : null
        );

        $res = self::postJson($franq['api_facturacion_url'], $payload, $franq['api_key_facturacion']);

        if ($res['http_code'] >= 200 && $res['http_code'] < 300) {
            return array('ejecutado' => true, 'success' => true, 'detalle' => 'Venta notificada a la API de facturación de ' . $franq['razon_social'] . '.');
        }

        return array(
            'ejecutado' => true,
            'success'   => false,
            'detalle'   => 'La API de facturación del franquiciado respondió HTTP ' . $res['http_code'] . '. Reintente manualmente o revise la configuración.'
        );
    }

    /**
     * Registra el resultado de una integración como actividad del lead.
     */
    public static function registrarResultado($leadId, $asunto, $resultado) {
        $db = Database::getInstance();
        $prefijo = $resultado['success'] ? '✔ ' : ($resultado['ejecutado'] ? '✖ ' : '⚠ ');
        $db->insert('actividades_crm', array(
            'lead_id'    => $leadId,
            'usuario_id' => null,
            'tipo'       => 'sistema',
            'direccion'  => 'interna',
            'asunto'     => $asunto,
            'detalles'   => $prefijo . $resultado['detalle']
        ));
    }

    // ─────────────────────────────────────────────────────────────────────────

    private static function configGrupo($db, $claves) {
        $out = array();
        foreach ($claves as $clave) {
            $row = $db->fetchOne("SELECT valor FROM config_sistema WHERE clave = :c LIMIT 1", array('c' => $clave));
            $out[$clave] = $row ? trim($row['valor']) : '';
        }
        return $out;
    }

    private static function postForm($url, $payload, $apiKey) {
        return self::curlPost($url, http_build_query($payload), 'application/x-www-form-urlencoded', $apiKey);
    }

    private static function postJson($url, $payload, $apiKey) {
        return self::curlPost($url, json_encode($payload), 'application/json', $apiKey);
    }

    private static function curlPost($url, $body, $contentType, $apiKey) {
        $headers = array('Content-Type: ' . $contentType);
        if (!empty($apiKey)) {
            $headers[] = 'X-API-KEY: ' . $apiKey;
        }

        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        $respuesta = curl_exec($ch);
        $code      = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $err       = curl_error($ch);
        curl_close($ch);

        if ($respuesta === false) {
            error_log('[IntegracionesHelper] cURL error: ' . $err . ' → ' . $url);
            return array('http_code' => 0, 'body' => '', 'data' => null);
        }

        return array('http_code' => $code, 'body' => $respuesta, 'data' => json_decode($respuesta, true));
    }
}
