<?php
/* Copyright (C) 2026 Alles Watt lauft
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 */

/**
 * Class MediumType
 * Manages cable/wire types (Kabeltypen) for connections
 */
class MediumType extends CommonObject
{
	public $element = 'mediumtype';
	public $table_element = 'kundenkarte_medium_type';

	public $ref;
	public $label;
	public $label_short;
	public $description;
	public $fk_system;
	public $category;
	public $default_spec;
	public $available_specs;  // JSON array
	public $color;
	public $picto;
	public $fk_product;
	public $is_system;
	public $position;
	public $active;

	public $date_creation;
	public $fk_user_creat;
	public $fk_user_modif;

	// Loaded properties
	public $system_label;
	public $system_code;

	// Category constants
	const CAT_STROMKABEL = 'stromkabel';
	const CAT_NETZWERKKABEL = 'netzwerkkabel';
	const CAT_LWL = 'lwl';
	const CAT_KOAX = 'koax';
	const CAT_SONSTIGES = 'sonstiges';

	/**
	 * Constructor
	 *
	 * @param DoliDB $db Database handler
	 */
	public function __construct($db)
	{
		$this->db = $db;
	}

	/**
	 * Create object in database
	 *
	 * @param User $user User that creates
	 * @return int Return integer <0 if KO, Id of created object if OK
	 */
	public function create($user)
	{
		global $conf;

		$error = 0;
		$now = dol_now();

		if (empty($this->ref) || empty($this->label)) {
			$this->error = 'ErrorMissingParameters';
			return -1;
		}

		$this->db->begin();

		$sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
		$sql .= "entity, ref, label, label_short, description, fk_system, category,";
		$sql .= " default_spec, available_specs, color, picto, fk_product,";
		$sql .= " is_system, position, active, date_creation, fk_user_creat";
		$sql .= ") VALUES (";
		$sql .= "0"; // entity 0 = global
		$sql .= ", '".$this->db->escape($this->ref)."'";
		$sql .= ", '".$this->db->escape($this->label)."'";
		$sql .= ", ".($this->label_short ? "'".$this->db->escape($this->label_short)."'" : "NULL");
		$sql .= ", ".($this->description ? "'".$this->db->escape($this->description)."'" : "NULL");
		$sql .= ", ".((int) $this->fk_system);
		$sql .= ", ".($this->category ? "'".$this->db->escape($this->category)."'" : "NULL");
		$sql .= ", ".($this->default_spec ? "'".$this->db->escape($this->default_spec)."'" : "NULL");
		$sql .= ", ".($this->available_specs ? "'".$this->db->escape($this->available_specs)."'" : "NULL");
		$sql .= ", ".($this->color ? "'".$this->db->escape($this->color)."'" : "NULL");
		$sql .= ", ".($this->picto ? "'".$this->db->escape($this->picto)."'" : "NULL");
		$sql .= ", ".($this->fk_product > 0 ? ((int) $this->fk_product) : "NULL");
		$sql .= ", 0"; // is_system = 0 for user-created
		$sql .= ", ".((int) $this->position);
		$sql .= ", ".((int) ($this->active !== null ? $this->active : 1));
		$sql .= ", '".$this->db->idate($now)."'";
		$sql .= ", ".((int) $user->id);
		$sql .= ")";

		$resql = $this->db->query($sql);
		if (!$resql) {
			$error++;
			$this->errors[] = "Error ".$this->db->lasterror();
		}

		if (!$error) {
			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
		}

		if ($error) {
			$this->db->rollback();
			return -1 * $error;
		} else {
			$this->db->commit();
			return $this->id;
		}
	}

	/**
	 * Load object from database
	 *
	 * @param int $id ID of record
	 * @return int Return integer <0 if KO, 0 if not found, >0 if OK
	 */
	public function fetch($id)
	{
		$sql = "SELECT t.*, s.label as system_label, s.code as system_code";
		$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system as s ON t.fk_system = s.rowid";
		$sql .= " WHERE t.rowid = ".((int) $id);

		$resql = $this->db->query($sql);
		if ($resql) {
			if ($this->db->num_rows($resql)) {
				$obj = $this->db->fetch_object($resql);

				$this->id = $obj->rowid;
				$this->entity = $obj->entity;
				$this->ref = $obj->ref;
				$this->label = $obj->label;
				$this->label_short = $obj->label_short;
				$this->description = $obj->description;
				$this->fk_system = $obj->fk_system;
				$this->category = $obj->category;
				$this->default_spec = $obj->default_spec;
				$this->available_specs = $obj->available_specs;
				$this->color = $obj->color;
				$this->picto = $obj->picto;
				$this->fk_product = $obj->fk_product;
				$this->is_system = $obj->is_system;
				$this->position = $obj->position;
				$this->active = $obj->active;
				$this->date_creation = $this->db->jdate($obj->date_creation);
				$this->fk_user_creat = $obj->fk_user_creat;
				$this->fk_user_modif = $obj->fk_user_modif;

				$this->system_label = $obj->system_label;
				$this->system_code = $obj->system_code;

				$this->db->free($resql);
				return 1;
			} else {
				$this->db->free($resql);
				return 0;
			}
		} else {
			$this->error = $this->db->lasterror();
			return -1;
		}
	}

	/**
	 * Update object in database
	 *
	 * @param User $user User that modifies
	 * @return int Return integer <0 if KO, >0 if OK
	 */
	public function update($user)
	{
		$error = 0;

		$this->db->begin();

		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
		$sql .= " ref = '".$this->db->escape($this->ref)."'";
		$sql .= ", label = '".$this->db->escape($this->label)."'";
		$sql .= ", label_short = ".($this->label_short ? "'".$this->db->escape($this->label_short)."'" : "NULL");
		$sql .= ", description = ".($this->description ? "'".$this->db->escape($this->description)."'" : "NULL");
		$sql .= ", fk_system = ".((int) $this->fk_system);
		$sql .= ", category = ".($this->category ? "'".$this->db->escape($this->category)."'" : "NULL");
		$sql .= ", default_spec = ".($this->default_spec ? "'".$this->db->escape($this->default_spec)."'" : "NULL");
		$sql .= ", available_specs = ".($this->available_specs ? "'".$this->db->escape($this->available_specs)."'" : "NULL");
		$sql .= ", color = ".($this->color ? "'".$this->db->escape($this->color)."'" : "NULL");
		$sql .= ", picto = ".($this->picto ? "'".$this->db->escape($this->picto)."'" : "NULL");
		$sql .= ", fk_product = ".($this->fk_product > 0 ? ((int) $this->fk_product) : "NULL");
		$sql .= ", position = ".((int) $this->position);
		$sql .= ", active = ".((int) $this->active);
		$sql .= ", fk_user_modif = ".((int) $user->id);
		$sql .= " WHERE rowid = ".((int) $this->id);

		$resql = $this->db->query($sql);
		if (!$resql) {
			$error++;
			$this->errors[] = "Error ".$this->db->lasterror();
		}

		if ($error) {
			$this->db->rollback();
			return -1 * $error;
		} else {
			$this->db->commit();
			return 1;
		}
	}

	/**
	 * Delete object in database
	 *
	 * @param User $user User that deletes
	 * @return int Return integer <0 if KO, >0 if OK
	 */
	public function delete($user)
	{
		// Cannot delete system types
		if ($this->is_system) {
			$this->error = 'ErrorCannotDeleteSystemType';
			return -2;
		}

		$error = 0;
		$this->db->begin();

		$sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element." WHERE rowid = ".((int) $this->id);
		$resql = $this->db->query($sql);
		if (!$resql) {
			$error++;
			$this->errors[] = "Error ".$this->db->lasterror();
		}

		if ($error) {
			$this->db->rollback();
			return -1 * $error;
		} else {
			$this->db->commit();
			return 1;
		}
	}

	/**
	 * Fetch all medium types for a system
	 *
	 * @param int $systemId System ID (0 = all)
	 * @param int $activeOnly Only active types
	 * @return array Array of MediumType objects
	 */
	public function fetchAllBySystem($systemId = 0, $activeOnly = 1)
	{
		$results = array();

		$sql = "SELECT t.*, s.label as system_label, s.code as system_code";
		$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system as s ON t.fk_system = s.rowid";
		$sql .= " WHERE 1 = 1";
		if ($systemId > 0) {
			// Show types for this system AND global types (fk_system = 0)
			$sql .= " AND (t.fk_system = ".((int) $systemId)." OR t.fk_system = 0)";
		}
		if ($activeOnly) {
			$sql .= " AND t.active = 1";
		}
		$sql .= " ORDER BY t.category ASC, t.position ASC, t.label ASC";

		$resql = $this->db->query($sql);
		if ($resql) {
			while ($obj = $this->db->fetch_object($resql)) {
				$type = new MediumType($this->db);
				$type->id = $obj->rowid;
				$type->ref = $obj->ref;
				$type->label = $obj->label;
				$type->label_short = $obj->label_short;
				$type->description = $obj->description;
				$type->fk_system = $obj->fk_system;
				$type->category = $obj->category;
				$type->default_spec = $obj->default_spec;
				$type->available_specs = $obj->available_specs;
				$type->color = $obj->color;
				$type->picto = $obj->picto;
				$type->fk_product = $obj->fk_product;
				$type->is_system = $obj->is_system;
				$type->position = $obj->position;
				$type->active = $obj->active;
				$type->system_label = $obj->system_label;
				$type->system_code = $obj->system_code;

				$results[] = $type;
			}
			$this->db->free($resql);
		}

		return $results;
	}

	/**
	 * Fetch all types grouped by category
	 *
	 * @param int $systemId System ID (0 = all)
	 * @return array Associative array: category => array of MediumType objects
	 */
	public function fetchGroupedByCategory($systemId = 0)
	{
		$all = $this->fetchAllBySystem($systemId, 1);
		$grouped = array();

		foreach ($all as $type) {
			$cat = $type->category ?: 'sonstiges';
			if (!isset($grouped[$cat])) {
				$grouped[$cat] = array();
			}
			$grouped[$cat][] = $type;
		}

		return $grouped;
	}

	/**
	 * Get available specs as array
	 *
	 * @return array Array of specification strings
	 */
	public function getAvailableSpecsArray()
	{
		if (empty($this->available_specs)) {
			return array();
		}
		$specs = json_decode($this->available_specs, true);
		return is_array($specs) ? $specs : array();
	}

	/**
	 * Get category label
	 *
	 * @return string Translated category label
	 */
	public function getCategoryLabel()
	{
		global $langs;

		switch ($this->category) {
			case self::CAT_STROMKABEL:
				return $langs->trans('MediumCatStromkabel');
			case self::CAT_NETZWERKKABEL:
				return $langs->trans('MediumCatNetzwerkkabel');
			case self::CAT_LWL:
				return $langs->trans('MediumCatLWL');
			case self::CAT_KOAX:
				return $langs->trans('MediumCatKoax');
			case self::CAT_SONSTIGES:
			default:
				return $langs->trans('MediumCatSonstiges');
		}
	}

	/**
	 * Get all category options
	 *
	 * @return array category_code => translated_label
	 */
	public static function getCategoryOptions()
	{
		global $langs;

		return array(
			self::CAT_STROMKABEL => $langs->trans('MediumCatStromkabel'),
			self::CAT_NETZWERKKABEL => $langs->trans('MediumCatNetzwerkkabel'),
			self::CAT_LWL => $langs->trans('MediumCatLWL'),
			self::CAT_KOAX => $langs->trans('MediumCatKoax'),
			self::CAT_SONSTIGES => $langs->trans('MediumCatSonstiges')
		);
	}
}
