<?php
/**
 * ASISMA CRM - Catálogo sincronizado desde Control Empresas.
 *
 * El catálogo del CRM (verticales, marcas, productos) NO se administra acá:
 * vive en la empresa matriz de Control Empresas y se sincroniza con el mapeo
 *   familia → vertical · subfamilia → marca · artículo → producto
 * Los precios salen de las listas de precios de la matriz:
 *   - lista general FRANQUICIADOS (CE_LISTA_FRANQUICIADOS_ID) → productos.precio_*
 *   - lista propia de cada franquiciado-cliente → tabla precios_franquiciado
 * Mapeo de precios: PRECIO_VENTA_NETO → precio mínimo, PRECIO_VENTA_PUBLICO →
 * precio sugerido (si no hay público, se usa el neto).
 *
 * Config en config_sistema: CE_PROVISION_URL, CE_PROVISION_API_KEY,
 * CE_EMPRESA_MATRIZ_ID, CE_LISTA_FRANQUICIADOS_ID.
 */
class CatalogoCeHelper {

    public static function config() {
        $db = Database::getInstance();
        $out = array();
        $claves = array('CE_PROVISION_URL', 'CE_PROVISION_API_KEY', 'CE_EMPRESA_MATRIZ_ID', 'CE_LISTA_FRANQUICIADOS_ID');
        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;
    }

    /** El catálogo queda de SOLO LECTURA en el CRM cuando la matriz está enlazada. */
    public static function activo() {
        $cfg = self::config();
        return !empty($cfg['CE_PROVISION_URL']) && !empty($cfg['CE_PROVISION_API_KEY']) && !empty($cfg['CE_EMPRESA_MATRIZ_ID']);
    }

    private static function llamar($cfg, $payload) {
        $payload['api_key'] = $cfg['CE_PROVISION_API_KEY'];
        $ch = curl_init($cfg['CE_PROVISION_URL']);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($payload));
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, 90);
        $respuesta = curl_exec($ch);
        $err = curl_error($ch);
        curl_close($ch);
        if ($respuesta === false) {
            error_log('[CatalogoCeHelper] cURL: ' . $err);
            return null;
        }
        return json_decode($respuesta, true);
    }

    /**
     * Sincroniza el catálogo completo desde la matriz de Control Empresas.
     * Devuelve array('success' => bool, 'detalle' => string, 'resumen' => array).
     */
    public static function sincronizar() {
        $cfg = self::config();
        if (!self::activo()) {
            return array('success' => false, 'detalle' => 'La matriz de Control Empresas no está configurada (CE_EMPRESA_MATRIZ_ID).');
        }

        $data = self::llamar($cfg, array('action' => 'catalogo', 'empresa_id' => (int)$cfg['CE_EMPRESA_MATRIZ_ID']));
        if (!$data || empty($data['success'])) {
            $motivo = ($data && isset($data['message'])) ? $data['message'] : 'sin respuesta del webservice';
            return array('success' => false, 'detalle' => 'No se pudo leer el catálogo de Control Empresas: ' . $motivo);
        }

        // Índice de precios: [lista][articulo] = array(neto, publico)
        $precios = array();
        foreach ($data['precios'] as $p) {
            $precios[$p['lista_id']][$p['articulo_id']] = $p;
        }
        $listaGeneral = (int)$cfg['CE_LISTA_FRANQUICIADOS_ID'];

        $db = Database::getInstance();
        $resumen = array('verticales' => 0, 'marcas' => 0, 'productos' => 0, 'desactivados' => 0, 'franquiciados_con_lista' => 0);

        $db->beginTransaction();
        try {
            // ── VERTICALES ← familias ──
            $mapaVertical = array(); // familia CE → vertical CRM
            $familiasVistas = array();
            foreach ($data['familias'] as $f) {
                $familiasVistas[] = (int)$f['id'];
                $existente = $db->fetchOne("SELECT id FROM verticales WHERE ce_family_id = :cid", array('cid' => $f['id']));
                if ($existente) {
                    $db->update('verticales', array('nombre' => $f['nombre'], 'activa' => 1), 'id = :id', array('id' => $existente['id']));
                    $mapaVertical[(int)$f['id']] = (int)$existente['id'];
                } else {
                    $vid = $db->insert('verticales', array(
                        'nombre' => $f['nombre'], 'descripcion' => 'Familia de Control Empresas',
                        'ce_family_id' => (int)$f['id'], 'activa' => 1
                    ));
                    $mapaVertical[(int)$f['id']] = (int)$vid;
                }
                $resumen['verticales']++;
            }
            // Las que ya no existen en CE se desactivan (si CE quedó vacío, TODAS)
            $db->query("UPDATE verticales SET activa = 0 WHERE ce_family_id IS NOT NULL" .
                (!empty($familiasVistas) ? " AND ce_family_id NOT IN (" . implode(',', $familiasVistas) . ")" : ""));

            // ── MARCAS ← subfamilias ──
            $mapaMarca = array(); // subfamilia CE → marca CRM
            $subfamiliasVistas = array();
            foreach ($data['subfamilias'] as $sf) {
                if (!isset($mapaVertical[(int)$sf['familia_id']])) continue;
                $subfamiliasVistas[] = (int)$sf['id'];
                $verticalId = $mapaVertical[(int)$sf['familia_id']];
                $existente = $db->fetchOne("SELECT id FROM marcas WHERE ce_subfamily_id = :cid", array('cid' => $sf['id']));
                if ($existente) {
                    $db->update('marcas', array('nombre' => $sf['nombre'], 'vertical_id' => $verticalId, 'activa' => 1),
                                'id = :id', array('id' => $existente['id']));
                    $mapaMarca[(int)$sf['id']] = (int)$existente['id'];
                } else {
                    $mid = $db->insert('marcas', array(
                        'vertical_id' => $verticalId, 'nombre' => $sf['nombre'],
                        'ce_subfamily_id' => (int)$sf['id'], 'activa' => 1
                    ));
                    $mapaMarca[(int)$sf['id']] = (int)$mid;
                }
                $resumen['marcas']++;
            }
            $db->query("UPDATE marcas SET activa = 0 WHERE ce_subfamily_id IS NOT NULL" .
                (!empty($subfamiliasVistas) ? " AND ce_subfamily_id NOT IN (" . implode(',', $subfamiliasVistas) . ")" : ""));

            // Marca "General" por vertical: para artículos sin subfamilia en CE
            $marcaGeneral = array(); // vertical CRM → marca id
            $obtenerMarcaGeneral = null; // se resuelve al vuelo más abajo

            // ── PRODUCTOS ← artículos ──
            $mapaProducto = array(); // articulo CE → producto CRM
            $articulosVistos = array();
            foreach ($data['articulos'] as $a) {
                if (!isset($mapaVertical[(int)$a['familia_id']])) continue;
                $articulosVistos[] = (int)$a['id'];
                $verticalId = $mapaVertical[(int)$a['familia_id']];

                // Marca: su subfamilia, o la marca "General" de la vertical
                if ($a['subfamilia_id'] && isset($mapaMarca[(int)$a['subfamilia_id']])) {
                    $marcaId = $mapaMarca[(int)$a['subfamilia_id']];
                } else {
                    if (!isset($marcaGeneral[$verticalId])) {
                        $g = $db->fetchOne(
                            "SELECT id FROM marcas WHERE vertical_id = :vid AND nombre = 'General' AND ce_subfamily_id IS NULL LIMIT 1",
                            array('vid' => $verticalId));
                        if ($g) {
                            $db->update('marcas', array('activa' => 1), 'id = :id', array('id' => $g['id']));
                            $marcaGeneral[$verticalId] = (int)$g['id'];
                        } else {
                            $marcaGeneral[$verticalId] = (int)$db->insert('marcas', array(
                                'vertical_id' => $verticalId, 'nombre' => 'General', 'activa' => 1
                            ));
                        }
                    }
                    $marcaId = $marcaGeneral[$verticalId];
                }

                // Precio general: lista FRANQUICIADOS (neto → mínimo, público → sugerido)
                $minimo = 0; $sugerido = 0;
                if ($listaGeneral && isset($precios[$listaGeneral][(int)$a['id']])) {
                    $pg = $precios[$listaGeneral][(int)$a['id']];
                    $minimo = (float)$pg['neto'];
                    $sugerido = (float)$pg['publico'] > 0 ? (float)$pg['publico'] : (float)$pg['neto'];
                }

                $campos = array(
                    'vertical_id' => $verticalId,
                    'marca_id' => $marcaId,
                    'nombre' => $a['nombre'] !== '' && $a['nombre'] !== null ? $a['nombre'] : ('Artículo ' . $a['id']),
                    'descripcion' => $a['descripcion'] !== null ? $a['descripcion'] : '',
                    'precio_minimo' => $minimo,
                    'precio_sugerido' => $sugerido,
                    'activo' => (int)$a['activo']
                );

                $existente = $db->fetchOne("SELECT id FROM productos WHERE ce_articulo_id = :cid", array('cid' => $a['id']));
                if ($existente) {
                    $db->update('productos', $campos, 'id = :id', array('id' => $existente['id']));
                    $mapaProducto[(int)$a['id']] = (int)$existente['id'];
                } else {
                    $campos['ce_articulo_id'] = (int)$a['id'];
                    $mapaProducto[(int)$a['id']] = (int)$db->insert('productos', $campos);
                }
                $resumen['productos']++;
            }
            $db->query("UPDATE productos SET activo = 0 WHERE ce_articulo_id IS NOT NULL" .
                (!empty($articulosVistos) ? " AND ce_articulo_id NOT IN (" . implode(',', $articulosVistos) . ")" : ""));

            // Las marcas "General" (sin subfamilia en CE) se apagan si su
            // vertical quedó inactiva o si ya no les queda ningún producto activo
            $db->query("UPDATE marcas m LEFT JOIN verticales v ON v.id = m.vertical_id
                        SET m.activa = 0
                        WHERE m.ce_subfamily_id IS NULL AND m.nombre = 'General'
                          AND (v.activa = 0 OR NOT EXISTS (
                              SELECT 1 FROM productos p WHERE p.marca_id = m.id AND p.activo = 1))");

            // ── PRECIOS POR FRANQUICIADO (según la lista de su cliente en la matriz) ──
            $listaPorCliente = array();
            foreach ($data['clientes'] as $c) $listaPorCliente[(int)$c['id']] = $c['lista_precio_id'] ? (int)$c['lista_precio_id'] : null;

            $franquiciados = $db->fetchAll(
                "SELECT f.id, ef.id AS empresa_id, ef.ce_cliente_matriz_id, ef.ce_lista_precio_id
                 FROM franquiciados f INNER JOIN empresas_franquiciados ef ON f.empresa_madre_id = ef.id
                 WHERE ef.ce_cliente_matriz_id IS NOT NULL");
            foreach ($franquiciados as $fr) {
                $lista = isset($listaPorCliente[(int)$fr['ce_cliente_matriz_id']]) ? $listaPorCliente[(int)$fr['ce_cliente_matriz_id']] : null;
                if ((string)$lista !== (string)$fr['ce_lista_precio_id']) {
                    $db->update('empresas_franquiciados', array('ce_lista_precio_id' => $lista), 'id = :id', array('id' => $fr['empresa_id']));
                }
                $db->delete('precios_franquiciado', 'franquiciado_id = :fid', array('fid' => $fr['id']));
                if ($lista && $lista != $listaGeneral && isset($precios[$lista])) {
                    foreach ($precios[$lista] as $articuloId => $p) {
                        if (!isset($mapaProducto[(int)$articuloId])) continue;
                        $db->insert('precios_franquiciado', array(
                            'franquiciado_id' => $fr['id'],
                            'producto_id' => $mapaProducto[(int)$articuloId],
                            'precio_minimo' => (float)$p['neto'],
                            'precio_sugerido' => (float)$p['publico'] > 0 ? (float)$p['publico'] : (float)$p['neto'],
                            'actualizado_at' => date('Y-m-d H:i:s')
                        ));
                    }
                    $resumen['franquiciados_con_lista']++;
                }
            }

            $db->commit();
        } catch (Exception $e) {
            $db->rollBack();
            error_log('[CatalogoCeHelper] Error sincronizando: ' . $e->getMessage());
            return array('success' => false, 'detalle' => 'Error al sincronizar: ' . $e->getMessage());
        }

        AuditHelper::log('sincronizar_catalogo_ce', 'productos', null, null, $resumen);
        return array(
            'success' => true,
            'detalle' => "Catálogo sincronizado desde Control Empresas: {$resumen['verticales']} verticales, {$resumen['marcas']} marcas, {$resumen['productos']} productos" .
                         ($resumen['franquiciados_con_lista'] ? ", precios propios para {$resumen['franquiciados_con_lista']} franquiciado(s)" : "") . ".",
            'resumen' => $resumen
        );
    }

    /**
     * Precio de un producto para un franquiciado: su lista propia si existe,
     * si no los precios generales del producto. Devuelve array(minimo, sugerido).
     */
    public static function precioParaFranquiciado($franquiciadoId, $productoId) {
        $db = Database::getInstance();
        if ($franquiciadoId) {
            $propio = $db->fetchOne(
                "SELECT precio_minimo, precio_sugerido FROM precios_franquiciado
                 WHERE franquiciado_id = :fid AND producto_id = :pid",
                array('fid' => (int)$franquiciadoId, 'pid' => (int)$productoId));
            if ($propio) return array('minimo' => (float)$propio['precio_minimo'], 'sugerido' => (float)$propio['precio_sugerido']);
        }
        $general = $db->fetchOne("SELECT precio_minimo, precio_sugerido FROM productos WHERE id = :id", array('id' => (int)$productoId));
        if ($general) return array('minimo' => (float)$general['precio_minimo'], 'sugerido' => (float)$general['precio_sugerido']);
        return array('minimo' => 0.0, 'sugerido' => 0.0);
    }
}
