<?php
/* Copyright (C) 2026 Alles Watt lauft
 *
 * AJAX-Endpunkt: Liefert Anlagen als Cytoscape.js Graph
 * Gebäude-Typen (type_system_code=GLOBAL) = Räume (Compound-Container)
 * Geräte-Typen = Geräte (Nodes innerhalb der Räume)
 * Hierarchie über fk_parent (wie im Baum)
 * Connections = Kabel-Edges zwischen Geräten
 */

if (!defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1');
if (!defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1');
if (!defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1');
if (!defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1');

$res = 0;
if (!$res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.php";
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
if (!$res) die("Include of main fails");

dol_include_once('/kundenkarte/class/anlageconnection.class.php');

header('Content-Type: application/json; charset=UTF-8');

$langs->loadLangs(array('kundenkarte@kundenkarte'));

$socId = GETPOSTINT('socid');
$contactId = GETPOSTINT('contactid');

$response = array('success' => false, 'error' => '');

// Berechtigungsprüfung
if (!$user->hasRight('kundenkarte', 'read')) {
	$response['error'] = $langs->trans('ErrorPermissionDenied');
	echo json_encode($response);
	exit;
}

if ($socId <= 0) {
	$response['error'] = 'Missing socid';
	echo json_encode($response);
	exit;
}

// Feld-Metadaten laden (field_code → Label, Display-Modus, Badge-Farbe pro Typ)
// Sortiert nach position → Reihenfolge wird in der Graph-Ansicht beibehalten
$fieldMeta = array(); // [fk_anlage_type][field_code] = {label, display_mode, badge_color, show_in_tree, show_in_hover}
$sqlFields = "SELECT fk_anlage_type, field_code, field_label, field_type, tree_display_mode, badge_color, show_in_tree, show_in_hover";
$sqlFields .= " FROM ".MAIN_DB_PREFIX."kundenkarte_anlage_type_field WHERE active = 1 ORDER BY position";
$resFields = $db->query($sqlFields);
if ($resFields) {
	while ($fObj = $db->fetch_object($resFields)) {
		if ($fObj->field_type === 'header') continue;
		$fieldMeta[(int)$fObj->fk_anlage_type][$fObj->field_code] = array(
			'label' => $fObj->field_label,
			'display' => $fObj->tree_display_mode ?: 'badge',
			'color' => $fObj->badge_color ?: '',
			'type' => $fObj->field_type,
			'show_in_tree' => (int) $fObj->show_in_tree,
			'show_in_hover' => (int) $fObj->show_in_hover,
		);
	}
	$db->free($resFields);
}

// Elemente laden - OHNE GLOBAL-System (das ist nur die separate Gebäudestruktur)
// Gebäude/Räume werden über den Typ erkannt (type_system_code = GLOBAL)
// Hierarchie kommt aus fk_parent (wie im Baum)
$sql = "SELECT a.rowid, a.label, a.fk_parent, a.fk_system, a.fk_anlage_type,";
$sql .= " a.field_values, a.fk_contact, a.graph_x, a.graph_y,";
$sql .= " t.label as type_label, t.picto as type_picto, t.color as type_color,";
$sql .= " s.code as system_code, s.label as system_label,";
$sql .= " ts.code as type_system_code,";
$sql .= " (SELECT COUNT(*) FROM ".MAIN_DB_PREFIX."kundenkarte_anlage_files f WHERE f.fk_anlage = a.rowid AND f.file_type IN ('image/jpeg','image/png','image/gif','image/webp')) as image_count,";
$sql .= " (SELECT COUNT(*) FROM ".MAIN_DB_PREFIX."kundenkarte_anlage_files f WHERE f.fk_anlage = a.rowid AND f.file_type NOT IN ('image/jpeg','image/png','image/gif','image/webp')) as doc_count";
$sql .= " FROM ".MAIN_DB_PREFIX."kundenkarte_anlage as a";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."kundenkarte_anlage_type as t ON a.fk_anlage_type = t.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system as s ON a.fk_system = s.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system as ts ON t.fk_system = ts.rowid";
$sql .= " WHERE a.fk_soc = ".(int)$socId;
$sql .= " AND s.code != 'GLOBAL'";
if ($contactId > 0) {
	$sql .= " AND a.fk_contact = ".(int)$contactId;
} else {
	// Auf Kunden-Ebene nur Elemente ohne Kontaktzuweisung (wie im Baum)
	$sql .= " AND (a.fk_contact IS NULL OR a.fk_contact = 0)";
}
$sql .= " AND a.status = 1";
$sql .= " ORDER BY a.fk_parent, a.rang, a.rowid";

$elements = array('nodes' => array(), 'edges' => array());
$nodeIds = array();
// Zwischenspeicher: rowid → isBuilding (für Compound-Entscheidung)
$nodeIsBuilding = array();
// Hierarchie-Kanten (Gerät→Gerät), werden durch echte Kabel ersetzt falls vorhanden
$hierarchyEdges = array();
// Zwischenspeicher: alle DB-Zeilen für Zwei-Pass-Verarbeitung
$rows = array();

$resql = $db->query($sql);
if ($resql) {
	// 1. Pass: Alle Zeilen laden und Gebäude-Typen merken
	while ($obj = $db->fetch_object($resql)) {
		$isBuilding = (!empty($obj->type_system_code) && $obj->type_system_code === 'GLOBAL');
		$nodeIsBuilding[(int)$obj->rowid] = $isBuilding;
		$nodeIds[$obj->rowid] = true;
		$rows[] = $obj;
	}
	$db->free($resql);

	// 2. Pass: Nodes und Hierarchie-Edges aufbauen
	foreach ($rows as $obj) {
		$isBuilding = $nodeIsBuilding[(int)$obj->rowid];

		$nodeId = 'n_'.$obj->rowid;

		$nodeData = array(
			'id' => $nodeId,
			'label' => $obj->label,
			'type_label' => $obj->type_label ?: '',
			'type_picto' => $obj->type_picto ?: '',
			'type_color' => $obj->type_color ?: '',
			'system_code' => $obj->system_code ?: '',
			'system_label' => $obj->system_label ?: '',
			'fk_parent' => (int) $obj->fk_parent,
			'fk_anlage_type' => (int) $obj->fk_anlage_type,
			'is_building' => $isBuilding,
			'image_count' => (int) $obj->image_count,
			'doc_count' => (int) $obj->doc_count,
			'graph_x' => $obj->graph_x !== null ? (float) $obj->graph_x : null,
			'graph_y' => $obj->graph_y !== null ? (float) $obj->graph_y : null,
		);

		// Feldwerte mit Metadaten (Label, Display-Modus, Badge-Farbe)
		// Iteration über $fieldMeta (nach position sortiert), nicht über $rawValues (JSON-Reihenfolge)
		// Aufteilen: fields = auf dem Node (show_in_tree=1), hover_fields = im Tooltip (show_in_hover=1)
		if (!empty($obj->field_values)) {
			$rawValues = json_decode($obj->field_values, true);
			if (is_array($rawValues) && !empty($rawValues)) {
				$typeId = (int) $obj->fk_anlage_type;
				$meta = isset($fieldMeta[$typeId]) ? $fieldMeta[$typeId] : array();
				$treeFields = array();
				$hoverFields = array();
				foreach ($meta as $code => $fm) {
					$val = isset($rawValues[$code]) ? $rawValues[$code] : null;
					if ($val === '' || $val === null) continue;
					// Checkbox-Werte anpassen
					if ($fm['type'] === 'checkbox') {
						$val = $val ? '1' : '0';
					}
					$fieldEntry = array(
						'label' => $fm['label'],
						'value' => $val,
						'display' => $fm['display'],
						'color' => $fm['color'],
						'type' => $fm['type'],
					);
					// Auf dem Node: nur Felder mit show_in_tree=1
					if (!empty($fm['show_in_tree'])) {
						$treeFields[] = $fieldEntry;
					}
					// Im Tooltip: nur Felder mit show_in_hover=1
					if (!empty($fm['show_in_hover'])) {
						$hoverFields[] = $fieldEntry;
					}
				}
				$nodeData['fields'] = $treeFields;
				$nodeData['hover_fields'] = $hoverFields;
			}
		}

		// Compound-Parent: NUR wenn Eltern-Node ein Gebäude/Raum ist
		// Gerät→Gerät Hierarchie wird als Kante dargestellt (nicht verschachtelt)
		$parentId = (int) $obj->fk_parent;
		if ($parentId > 0 && isset($nodeIds[$parentId])) {
			$parentIsBuilding = !empty($nodeIsBuilding[$parentId]);
			if ($parentIsBuilding) {
				// Gebäude/Raum als Container → Compound-Parent
				$nodeData['parent'] = 'n_'.$parentId;
			} else {
				// Gerät→Gerät → Hierarchie-Kante vormerken (wird ggf. durch Kabel ersetzt)
				$hierKey = min($parentId, (int)$obj->rowid).'_'.max($parentId, (int)$obj->rowid);
				$hierarchyEdges[$hierKey] = array(
					'data' => array(
						'id' => 'hier_'.$parentId.'_'.$obj->rowid,
						'source' => 'n_'.$parentId,
						'target' => 'n_'.$obj->rowid,
						'is_hierarchy' => true,
					),
					'classes' => 'hierarchy-edge'
				);
			}
		}

		$elements['nodes'][] = array(
			'data' => $nodeData,
			'classes' => $isBuilding ? 'building-node' : 'device-node'
		);
	}
}

// Verbindungen laden
$connObj = new AnlageConnection($db);
$connections = $connObj->fetchBySociete($socId, 0);

// Verwendete Kabeltypen für die Legende sammeln
$usedCableTypes = array();

// Kabel-Paare merken (um Hierarchie-Kanten zu ersetzen)
$cableConnectedPairs = array();

foreach ($connections as $conn) {
	// Nur Edges für tatsächlich geladene Nodes
	if (!isset($nodeIds[$conn->fk_source]) || !isset($nodeIds[$conn->fk_target])) {
		continue;
	}

	$isPassthrough = empty($conn->label) && empty($conn->medium_type_label) && empty($conn->medium_type_text) && empty($conn->medium_spec);

	// Edge-Label zusammenbauen
	$edgeLabel = '';
	$mediumType = !empty($conn->medium_type_label) ? $conn->medium_type_label : $conn->medium_type_text;
	if (!empty($mediumType)) {
		$edgeLabel = $mediumType;
		if (!empty($conn->medium_spec)) {
			$edgeLabel .= ' '.$conn->medium_spec;
		}
		if (!empty($conn->medium_length)) {
			$edgeLabel .= ', '.$conn->medium_length;
		}
	}

	// Farbe: aus Connection oder aus Medium-Type
	$color = $conn->medium_color;
	if (empty($color) && !empty($conn->fk_medium_type)) {
		// Farbe aus Medium-Type-Tabelle holen
		$sqlColor = "SELECT color, label_short FROM ".MAIN_DB_PREFIX."kundenkarte_medium_type WHERE rowid = ".(int)$conn->fk_medium_type;
		$resColor = $db->query($sqlColor);
		if ($resColor && $mtObj = $db->fetch_object($resColor)) {
			$color = $mtObj->color;
		}
	}

	// Kabeltyp für Legende merken
	if (!$isPassthrough && !empty($mediumType)) {
		$typeKey = $mediumType;
		if (!isset($usedCableTypes[$typeKey])) {
			$usedCableTypes[$typeKey] = array(
				'label' => $mediumType,
				'color' => $color ?: '#5a8a5a',
			);
		}
	}

	// Echte Kabelverbindung (nicht durchgeschleift) → Hierarchie-Kante überflüssig
	if (!$isPassthrough) {
		$src = (int) $conn->fk_source;
		$tgt = (int) $conn->fk_target;
		$pairKey = min($src, $tgt).'_'.max($src, $tgt);
		$cableConnectedPairs[$pairKey] = true;
	}

	$elements['edges'][] = array(
		'data' => array(
			'id' => 'conn_'.$conn->id,
			'source' => 'n_'.$conn->fk_source,
			'target' => 'n_'.$conn->fk_target,
			'label' => $edgeLabel,
			'medium_type' => $mediumType,
			'medium_spec' => $conn->medium_spec,
			'medium_length' => $conn->medium_length,
			'medium_color' => $color,
			'connection_id' => (int) $conn->id,
			'is_passthrough' => $isPassthrough,
		),
		'classes' => $isPassthrough ? 'passthrough-edge' : 'cable-edge'
	);
}

// Hierarchie-Kanten hinzufügen, aber nur wenn kein echtes Kabel zwischen den Geräten existiert
foreach ($hierarchyEdges as $hierKey => $hierEdge) {
	if (!isset($cableConnectedPairs[$hierKey])) {
		$elements['edges'][] = $hierEdge;
	}
}

// Prüfen ob gespeicherte Positionen vorhanden sind
$hasPositions = false;
foreach ($elements['nodes'] as $node) {
	if ($node['data']['graph_x'] !== null) {
		$hasPositions = true;
		break;
	}
}

$response['success'] = true;
$response['elements'] = $elements;
$response['cable_types'] = array_values($usedCableTypes);
$response['has_positions'] = $hasPositions;
$response['meta'] = array(
	'socid' => $socId,
	'contactid' => $contactId,
	'total_nodes' => count($elements['nodes']),
	'total_connections' => count($connections),
);

echo json_encode($response);
