<?php

class Traspaso_model extends CI_Model {

	/******************************** Funciones de Consulta **************************************/

	public function listado($filtros = [], $cantidad = []) {
		$this->db->from('traspasos');
		$this->db->where('deleted', 0);

		if ($filtros['estado'] != 'todos') {
			$this->db->where('estado_traspaso', $filtros['estado']);
		}
		if (!empty($filtros['origen'])) {
			$this->db->where('id_origen', $filtros['origen']);
		}
		if (!empty($filtros['destino'])) {
			$this->db->where('id_destino', $filtros['destino']);
		}
		if (!empty($filtros['solicitante'])) {
			$this->db->where('id_solicitante', $filtros['solicitante']);
		}

		$result['total'] = $this->db->count_all_results('', false);

		if (!empty($cantidad)) {
			if (count($cantidad) == 1) {
				$this->db->limit($cantidad[0]);
			} else {
				$this->db->limit($cantidad[1], $cantidad[0]);
			}
		}

		$this->db->order_by('id', 'DESC');
		$result['traspasos'] = $this->db->get()->result_array();

		foreach($result['traspasos'] as &$t) {

			// Cantidad de productos
			$this->db->select('count(id) as count');
			$this->db->from('productos_traspasos');
			$this->db->where('deleted', 0);
			$this->db->where('id_traspaso', $t['id']);
			$c = $this->db->get()->row_array();
			$t['productos'] = $c['count'];

			// Traer productos del traspaso + ps_id + cantidades
			$this->db->select('
				pt.solicitado,
				pt.preparado,
				pt.recibido,
				p.ps_id
			');
			$this->db->from('productos_traspasos pt');
			$this->db->join('productos p', 'p.id = pt.id_producto');
			$this->db->where('pt.deleted', 0);
			$this->db->where('pt.id_traspaso', $t['id']);
			$productos = $this->db->get()->result_array();

			$totalVenta = 0;

			foreach($productos as $p) {

				$cantidad = 0;

				// Definir cantidad según estado
				switch($t['estado_traspaso']) {
					case 1:
					case 2:
						$cantidad = $p['solicitado'];
						break;
					case 3:
						$cantidad = $p['preparado'];
						break;
					case 4:
						$cantidad = $p['recibido'];
						break;
					default:
						$cantidad = 0;
						break;
				}

				if (!empty($p['ps_id']) && $cantidad > 0) {
					$precio = $this->Producto->ps_prices($p['ps_id']);
					$totalVenta += ($precio * $cantidad);
				}
			}

			$t['total_venta'] = $totalVenta;
		}
		return $result;
	}
/*
	public function listado($filtros = [], $cantidad = []) {
		$this->db->from('traspasos');
		$this->db->where('deleted', 0);

		if ($filtros['estado'] != 'todos') {
			$this->db->where('estado_traspaso', $filtros['estado']);
		}
		if (!empty($filtros['origen'])) {
			$this->db->where('id_origen', $filtros['origen']);
		}
		if (!empty($filtros['destino'])) {
			$this->db->where('id_destino', $filtros['destino']);
		}
		if (!empty($filtros['solicitante'])) {
			$this->db->where('id_solicitante', $filtros['solicitante']);
		}

		// Consultar cantidad de resultados
		$result['total'] = $this->db->count_all_results('', false);

		// Condiciones de Paginación
		if (!empty($cantidad)) {
			if (count($cantidad) == 1) {
				$this->db->limit($cantidad[0]);
			}
			else {
				$this->db->limit($cantidad[1], $cantidad[0]);
			}
		}

		$this->db->order_by('id', 'DESC');

		$result['traspasos'] = $this->db->get()->result_array();

		// Cuenta SKUS distintos del traspaso
		foreach($result['traspasos'] as &$t) {
			$this->db->select('count(id) as count');
			$this->db->from('productos_traspasos');
			$this->db->where('deleted', 0);
			$this->db->where('id_traspaso', $t['id']);
			$c = $this->db->get()->row_array();
			$t['productos'] = $c['count'];
		}

		
		return $result;
	}
*/

	public function info($id) {
		$this->db->from('traspasos');
		$this->db->where('id', $id);
		$this->db->where('deleted', 0);
		$traspaso = $this->db->get()->row_array();

		$this->db->select('pt.*, p.nombre, p.id_proveedor, p.ps_id');
		$this->db->from('productos_traspasos pt');
		$this->db->join('productos p','pt.id_producto = p.id', 'left');
		$this->db->where('id_traspaso', $id);
		$this->db->where('pt.deleted', 0);
		$this->db->where('p.deleted', 0);
		$this->db->order_by('p.nombre', 'ASC');
		$traspaso['productos_traspasos'] = $this->db->get()->result_array();

		$CI =& get_instance();
		$CI->load->model('Producto_model', 'Producto');
		foreach ($traspaso['productos_traspasos'] as &$p ) {
			$p['id_image'] = $this->Producto->get_ps_image($p['ps_id']);
		}
		return $traspaso;
	}

	/**
	 * Toma traspaso para prepararlo
	 * Se guarda id de preparardor y se cambia estado a 2
	 */
	public function preparar($idTraspaso, $idPreparador) {
		// Busca Info del traspaso
		$this->db->from('traspasos');
		$this->db->where('id', $idTraspaso);
		$this->db->where('deleted', 0);
		$traspaso = $this->db->get()->row_array();

		// Verificar que Traspaso se encuentre en estado Solicitado
		if ($traspaso['estado_traspaso'] == 1) {
			$traspaso = [
				'estado_traspaso' => 2,
				'id_preparador' => $idPreparador
			];
			$this->db->where('id', $idTraspaso);
			if ($this->db->update('traspasos', $traspaso)) {
				$result['status'] = 'success';
			}
			else {
				$result['status'] = 'error';
				$result['message'] = 'Error al actualizar el traspaso';
			}
		}
		else {
			// Si estado ya se encuentra en preparación
			if ($traspaso['estado_traspaso'] == 2) {
				$result['status'] = 'error';
				$result['message'] = 'El traspaso ya se encuentra en preparación por otro usuario';
			}
			// En cualquier otro estado indica que no se puede tomar
			else {
				$result['message'] = 'El traspaso no se puede preparar';
			}
		}
		return $result;
	}


	public function automatico($idDestino = 0, $idCategoria = 0, $soloDeseados = 0) {
		$CI =& get_instance();
		$CI->load->model('Almacen_model', 'Almacen', true);
		$CI->load->model('Producto_model', 'Producto');

		// Busca productos deseados en tienda
		$deseados = $this->Almacen->monitor($idDestino, ['tipo' => 3, 'categoria' => $idCategoria]);

		$faltantes = [];
		$sugeridos = [];
		$requeridos = [];
		if (empty($soloDeseados)) {
			// Busca productos faltantes en tienda
			$faltantes = $this->Almacen->monitor($idDestino, ['tipo' => 2, 'categoria' => $idCategoria]);

			// Busca productos sugeridos en tienda
			$sugeridos = $this->Almacen->monitor($idDestino, ['tipo' => 4, 'categoria' => $idCategoria]);

			// Busca productos requeridos para retiro en tienda
			$requeridos = $this->Almacen->monitor($idDestino, ['tipo' => 6, 'categoria' => $idCategoria]);
		}

		$productos = [];

		foreach($faltantes as $p) {
			$nuevo = [
				'id' => '',
				'id_producto' => $p['id'],
				'solicitado' => 1,
				'nombre' => $p['nombre'],
				'id_proveedor' => $p['id_proveedor'],
				'ps_id' => $p['ps_id'],
				'id_image' => $this->Producto->get_ps_image($p['ps_id']),
				'ingreso' => 'Faltante'
			];
			$productos[$p['id']] = $nuevo;
		}

		// Se compara si deseados en almacen es mayor que disponibles en almacen
		foreach($deseados as $p) {
			if (empty($productos[$p['id']])) {
				if ($p['deseados_almacen'] < $p['deseados_max_almacen']) {
					$p['deseados_almacen'] = $p['deseados_max_almacen'];
				}

				if ($p['deseados_almacen'] <= $p['disponibles']) {
					$solicitar = $p['deseados_almacen'] - $p['disponibles_almacen'];
				}
				else {
					$solicitar = $p['disponibles'] - $p['disponibles_almacen'];
				}

				$nuevo = [
					'id' => '',
					'id_producto' => $p['id'],
					'solicitado' => $solicitar,
					'nombre' => $p['nombre'],
					'id_proveedor' => $p['id_proveedor'],
					'ps_id' => $p['ps_id'],
					'id_image' => $this->Producto->get_ps_image($p['ps_id']),
					'ingreso' => 'Deseado'
				];
				$productos[$p['id']] = $nuevo;
			}
			else {
				if ($p['deseados_almacen'] < $p['deseados_max_almacen']) {
					$p['deseados_almacen'] = $p['deseados_max_almacen'];
				}

				if ($p['deseados_almacen'] <= $p['disponibles']) {
					$solicitar = $p['deseados_almacen'] - $p['disponibles_almacen'];
				}
				else {
					$solicitar = $p['disponibles'] - $p['disponibles_almacen'];
				}

				if ($solicitar > $productos[$p['id']]['solicitado']) {
					$productos[$p['id']]['solicitado'] = $solicitar;
					$productos[$p['id']]['ingreso'] = 'Faltante';
				}
			}
		}

		foreach($sugeridos as $p) {
			if (empty($productos[$p['id']])) {
				if (ceil($p['vendidos_quincena']/2) > $p['disponibles_almacen']) {
					if (ceil($p['vendidos_quincena']/2) <= $p['disponibles']) {
						$solicitar = ceil($p['vendidos_quincena']/2) - $p['disponibles_almacen'];
					}
					else {
						$solicitar = $p['disponibles'] - $p['disponibles_almacen'];
					}
					$nuevo = [
						'id' => '',
						'id_producto' => $p['id'],
						'solicitado' => $solicitar,
						'nombre' => $p['nombre'],
						'id_proveedor' => $p['id_proveedor'],
						'ps_id' => $p['ps_id'],
						'id_image' => $this->Producto->get_ps_image($p['ps_id']),
						'ingreso' => 'Sugerido'
					];
					$productos[$p['id']] = $nuevo;
				}
			}
			else {
				$solicitar = 0;
				if (ceil($p['vendidos_quincena']/2) > $p['disponibles_almacen']) {
					if (ceil($p['vendidos_quincena']/2) <= $p['disponibles']) {
						$solicitar = ceil($p['vendidos_quincena']/2) - $p['disponibles_almacen'];
					}
					else {
						$solicitar = $p['disponibles'] - $p['disponibles_almacen'];
					}

					if ($solicitar > $productos[$p['id']]['solicitado']) {
						$productos[$p['id']]['solicitado'] = $solicitar;
						$productos[$p['id']]['ingreso'] = 'Sugerido';
					}
				}
			}
		}

		foreach($requeridos as $p) {
			$nuevo = [
				'id' => '',
				'id_producto' => $p['id'],
				'solicitado' => abs($p['disponibles_almacen']),
				'nombre' => $p['nombre'],
				'id_proveedor' => $p['id_proveedor'],
				'ps_id' => $p['ps_id'],
				'id_image' => $this->Producto->get_ps_image($p['ps_id']),
				'ingreso' => 'Requerido'
			];
			$productos[$p['id']] = $nuevo;
		}

		$traspaso = [];
		foreach ($productos as $p) {
			$traspaso[] = $p;
		}

		return $traspaso;
	}

	/******************************************** Utilidades *************************************/

	/**
	 * Entrega todos los datos necesarios para gestionar traspasos:
	 * Productos, almacenes, usuarios, estados_traspasos
	 */
	 
	public function datos_globales($data) {
		
		$data['usuariosActivos'] = $this->Usuario->lista(1);
		$data['usuarios'] = $this->Usuario->lista();

		$data['estadosTraspasos'] = [
			0 => 'Borrador',
			1 => 'Solicitado',
			2 => 'En Preparación',
			3 => 'Preparado',
			4 => 'Completado',
			5 => 'Cancelado'
		];

		$CI =& get_instance();
		$CI->load->model('Almacen_model', 'Almacen', true);
		$data['almacenes'] = $this->Almacen->lista(false);
		$data['almacenes_activos'] = $this->Almacen->lista(true);

		$CI->load->model('Producto_model', 'Producto', true);
		$data['productos'] = $this->Producto->lista();

		// Busca disponibilidad de productos en almacenes
		$data['info_productos'] = $this->Almacen->stock_productos();

		$CI->load->model('Proveedor_model', 'Proveedor');
		$data['proveedores'] = $this->Proveedor->lista();

		return $data;
	}


	/**************************************** Edición ********************************************/


	/**
	 * Guardar datos de un nuevo traspaso o edición
	 */
	public function guardar($data) {
		$res = $this->validar($data);
		if ($res['status'] == 'error') {
			return [
				'status' => 'error',
				'message' => implode('<br />', $res['errores'])
			];
		}

		// Convertir warnings/notices en excepciones solo para este bloque
		$oldHandler = set_error_handler(function($severity, $message, $file, $line) {
			throw new ErrorException($message, 0, $severity, $file, $line);
		});

		try {
			$this->db->trans_begin(); // Inicia la transacción

			// Crear traspaso si no viene ID
			if (empty($data['id'])) {
				$nuevoEstado = ($data['avanzar'] == 1) ? 1 : 0;
				$fechaSolicitud = ($data['avanzar'] == 1) ? date('Y-m-d H:i:s') : '';
				$traspaso = [
					'id_solicitante' => $data['id_solicitante'],
					'id_origen' => $data['id_origen'],
					'id_destino' => $data['id_destino'],
					'estado_traspaso' => $nuevoEstado,
					'descripcion' => $data['descripcion'],
					'observaciones_creacion' => $data['observaciones'],
					'fecha_solicitud' => $fechaSolicitud
				];
				$this->db->insert('traspasos', $traspaso);
				$idTraspaso = $this->db->insert_id();

				foreach($data['id_producto'] as $key => $idProducto) {
					if (!empty($idProducto) && !empty($data['solicitado'][$key])) {
						$productoTraspaso = [
							'id_traspaso' => $idTraspaso,
							'id_producto' => $idProducto,
							'solicitado' => $data['solicitado'][$key],
						];
						$this->db->insert('productos_traspasos', $productoTraspaso);
					}
				}
			} else {
				// Edición de traspaso existente
				$this->db->where('id', $data['id']);
				$this->db->where('deleted', 0);
				$traspasoAnterior = $this->db->get('traspasos')->row_array();
				$idTraspaso = $data['id'];

				if ($traspasoAnterior['estado_traspaso'] != $data['estado_traspaso']) {
					throw new Exception('El traspaso ha cambiado de estado, no puede ser editado');
				}

				// Estado en creación
				if ($traspasoAnterior['estado_traspaso'] == 0) {
					$nuevoEstado = ($data['avanzar'] == 1) ? 1 : 0;
					$fechaSolicitud = ($data['avanzar'] == 1) ? date('Y-m-d H:i:s') : '';
					$traspaso = [
						'id_origen' => $data['id_origen'],
						'id_destino' => $data['id_destino'],
						'estado_traspaso' => $nuevoEstado,
						'descripcion' => $data['descripcion'],
						'observaciones_creacion' => $data['observaciones'],
						'fecha_solicitud' => $fechaSolicitud
					];
					$this->db->where('id', $idTraspaso);
					$this->db->update('traspasos', $traspaso);

					// Eliminar productos antiguos
					$this->db->where('id_traspaso', $idTraspaso);
					$this->db->where('deleted', 0);
					$this->db->update('productos_traspasos', ['deleted' => 1]);

					// Insertar productos nuevos
					foreach($data['id_producto'] as $key => $idProducto) {
						if (!empty($idProducto) && !empty($data['solicitado'][$key])) {
							$productoTraspaso = [
								'id_traspaso' => $idTraspaso,
								'id_producto' => $idProducto,
								'solicitado' => $data['solicitado'][$key],
							];
							$this->db->insert('productos_traspasos', $productoTraspaso);
						}
					}
				}

				// Traspaso en preparación
				if ($traspasoAnterior['estado_traspaso'] == 2) {

					$nuevoEstado = ($data['avanzar'] == 1) ? 3 : 2;
					$fechaPreparacion = ($data['avanzar'] == 1) ? date('Y-m-d H:i:s') : '';

					$traspaso = [
						'estado_traspaso' => $nuevoEstado,
						'observaciones_preparacion' => $data['observaciones'],
						'fecha_preparacion' => $fechaPreparacion
					];

					$this->db->where('id', $idTraspaso);
					$this->db->update('traspasos', $traspaso);

					$almacenOrigen = $traspasoAnterior['id_origen'];
					$idProductos = [];

					foreach ($data['id_producto'] as $key => $idProducto) {

						if (!empty($idProducto) && isset($data['preparado'][$key])) {

							// Siempre guardar preparado
							if (!empty($data['validado'][$key])) {
								$productoTraspaso['preparado'] = $data['preparado'][$key];
								$productoTraspaso['razon_preparado'] = $data['diferencia'][$key]
									? $data['razon_preparado'][$key]
									: 0;
							} else {
								$productoTraspaso = [
									'preparado' => 0,
									'razon_preparado' => 0,
								];
							}

							$this->db->where('id', $data['id_producto_traspaso'][$key]);
							$this->db->update('productos_traspasos', $productoTraspaso);

							// SOLO SI AVANZA CAMBIA STOCK A EN TRÁNSITO
							if ($data['avanzar'] == 1) {

								$cantidadPreparada = (int)$data['preparado'][$key];

								if ($cantidadPreparada > 0) {
									$this->db->where('id_producto', $idProducto);
									$this->db->where('id_almacen', $almacenOrigen);
									$productoAlmacen = $this->db->get('almacenes_productos')->row_array();

									if ($productoAlmacen) {
										$updateAlmacen = [
											'disponibles' => $productoAlmacen['disponibles'] - $cantidadPreparada,
											'en_transito' => $productoAlmacen['en_transito'] + $cantidadPreparada
										];

										$this->db->where('id', $productoAlmacen['id']);
										$this->db->update('almacenes_productos', $updateAlmacen);
									}
								}
							}
							$idProductos[] = $idProducto;
						}
					}

					// Ajusta stock PS solo cuando avanza
					if ($data['avanzar'] == 1) {
						$this->Producto->ajusta_stock_ps($idProductos);
					}
				}
			}

			$this->db->trans_commit();
			return [
				'status' => 'success',
				'id_traspaso' => $idTraspaso
			];

		} catch (Exception $e) {
			$this->db->trans_rollback();
			return [
				'status' => 'error',
				'message' => $e->getMessage()
			];
		} finally {
			restore_error_handler(); // Restaurar el handler original
		}
	}



	public function eliminar($id) {
		//revisar si viene id y si viene se hace update
		if (!empty($id)) {
			//Consulta datos de traspaso
			$this->db->select('estado_traspaso');
			$this->db->from('traspasos');
			$this->db->where('id', $id);
			$traspasoAnterior = $this->db->get()->row_array();

			if ($traspasoAnterior['estado_traspaso'] == 4) {
				$return['status'] = 'error';
				$return['message'] = 'No se puede eliminar un traspaso completado';
				return $return;
			}

			//Elimina traspaso
			$this->db->set('deleted', 1, FALSE);
			$this->db->where('id', $id);
			$this->db->update('traspasos');

			// Elimina productos_traspasos
			$this->db->set('deleted', 1, FALSE);
			$this->db->where('id_traspaso', $id);
			$this->db->update('productos_traspasos');

			// --- ACTUALIZA STOCK DE PRODUCTOS DEL TRASPASO ---
			$this->db->select('DISTINCT id_producto');
			$this->db->from('productos_traspasos');
			$this->db->where('id_traspaso', $id);
			$productos = $this->db->get()->result_array();

			if (!empty($productos)) {
				foreach ($productos as $p) {
					$idProducto = intval($p['id_producto']);
					if ($idProducto > 0) {
						$this->Producto->actualiza_stocks($idProducto);
					}
				}
			}
		}

		$return['status'] = 'success';
		$return['message'] = 'Traspaso Eliminado';
		return $return;
	}

	public function cancelar($id) {
		//revisar si viene id y si viene se hace update
		if (!empty($id)) {
			//Consulta datos de traspaso
			$this->db->select('estado_traspaso');
			$this->db->from('traspasos');
			$this->db->where('id', $id);
			$traspasoAnterior = $this->db->get()->row_array();

			if ($traspasoAnterior['estado_traspaso'] == 4) {
				$return['status'] = 'error';
				$return['message'] = 'No se puede cancelar un traspaso completado';
				return $return;
			}

			// Cancela traspaso
			$this->db->set('estado_traspaso', 5, FALSE);
			$this->db->where('id', $id);
			$this->db->update('traspasos');

			// --- Actualiza stock de los productos del traspaso ---
			$this->db->distinct();
			$this->db->select('id_producto');
			$this->db->from('productos_traspasos');
			$this->db->where('id_traspaso', $id);
			$productos = $this->db->get()->result_array();

			if (!empty($productos)) {
				foreach ($productos as $p) {
					$idProducto = intval($p['id_producto']);
					if ($idProducto > 0) {
						$this->Producto->actualiza_stocks($idProducto);
					}
				}
			}
		}

		$return['status'] = 'success';
		$return['message'] = 'Traspaso Cancelado';
		return $return;
	}

	public function liberar($id) {
		//revisar si viene id y si viene se hace update
		if (!empty($id)) {
			//Consulta datos de traspaso
			$this->db->select('estado_traspaso');
			$this->db->from('traspasos');
			$this->db->where('id', $id);
			$traspasoAnterior = $this->db->get()->row_array();

			if ($traspasoAnterior['estado_traspaso'] == 4) {
				$return['status'] = 'error';
				$return['message'] = 'No se puede liberar un traspaso completado';
				return $return;
			}

			if ($traspasoAnterior['estado_traspaso'] == 3) {
				$return['status'] = 'error';
				$return['message'] = 'No se puede liberar un traspaso ya preparado';
				return $return;
			}

			// Liberar Traspaso
			$this->db->set('estado_traspaso', 1, FALSE);
			$this->db->set('id_preparador', 0, FALSE);
			$this->db->where('id', $id);
			$this->db->update('traspasos');
		}

		$return['status'] = 'success';
		$return['message'] = 'Traspaso liberado';
		return $return;
	}

	/**
	 * Completa el traspaso con id = $id
	 * Transfiere stock físico y disponible entre almacenes
	 * Evita cambios duplicados si vienen ids repetidos
	 */
	public function completar($data) 	{
		if (empty($data['id'])) {
			return ['status' => 'error', 'message' => 'ID inválido'];
		}

		$this->db->trans_begin();

		// Lock traspaso //
		$traspaso = $this->db->query(
			'SELECT estado_traspaso, id_origen, id_destino
			FROM traspasos
			WHERE id = ? AND deleted = 0
			FOR UPDATE',
			[$data['id']]
		)->row_array();

		if (empty($traspaso)) {
			$this->db->trans_rollback();
			return ['status' => 'error', 'message' => 'Traspaso no encontrado'];
		}

		if ((int)$traspaso['estado_traspaso'] === 4) {
			$this->db->trans_rollback();
			return ['status' => 'error', 'message' => 'Traspaso ya se encuentra completado'];
		}

		// Conteo diferencias //
		$diferenciasRecepcion = 0;
		foreach ($data['diferencia'] as $dif) {
			if ($dif) {
				$diferenciasRecepcion++;
			}
		}

		// Marcar traspaso completado //
		$this->db->where('id', $data['id']);
		$this->db->update('traspasos', [
			'estado_traspaso' => 4,
			'fecha_completado' => date('Y-m-d H:i:s'),
			'id_receptor' => $data['id_solicitante'],
			'observaciones_recepcion' => $data['observaciones'],
			'diferencias_recepcion' => $diferenciasRecepcion
		]);

		$idProductos = [];

		foreach ($data['id_producto'] as $key => $idProducto) {

			$idPT     = $data['id_producto_traspaso'][$key];
			$recibido = (int)$data['recibido'][$key];

			// Lock producto traspaso //
			$pt = $this->db->query(
				'SELECT preparado, impacto_stock
				FROM productos_traspasos
				WHERE id = ?
				FOR UPDATE',
				[$idPT]
			)->row_array();

			if (empty($pt) || (int)$pt['impacto_stock'] === 1) {
				continue;
			}

			$preparado = (int)$pt['preparado'];

			// Actualización recepción //
			$this->db->where('id', $idPT);
			$this->db->update('productos_traspasos', [
				'recibido' => $recibido,
				'razon_recibido' => $data['diferencia'][$key] ? $data['razon_recibido'][$key] : 0
			]);

			// Origen //
			$almacenOrigen = $this->db->query(
				'SELECT * FROM almacenes_productos
				WHERE id_producto = ? AND id_almacen = ? AND deleted = 0
				FOR UPDATE',
				[$idProducto, $traspaso['id_origen']]
			)->row_array();

			$stockOrigen      = (int)($almacenOrigen['stock'] ?? 0);
			$reservadosOrigen = (int)($almacenOrigen['reservados'] ?? 0);
			$enTransitoOrigen = (int)($almacenOrigen['en_transito'] ?? 0);

			$nuevoStockOrigen = $stockOrigen - $recibido;
			$nuevoEnTransito  = max(0, $enTransitoOrigen - $preparado);
			$nuevosDispOrigen = $nuevoStockOrigen - $reservadosOrigen - $nuevoEnTransito;

			$this->db->where('id', $almacenOrigen['id']);
			$this->db->update('almacenes_productos', [
				'stock' => $nuevoStockOrigen,
				'en_transito' => $nuevoEnTransito,
				'disponibles' => $nuevosDispOrigen
			]);

			// Destino //
			$almacenDestino = $this->db->query(
				'SELECT * FROM almacenes_productos
				WHERE id_producto = ? AND id_almacen = ? AND deleted = 0
				FOR UPDATE',
				[$idProducto, $traspaso['id_destino']]
			)->row_array();

			if (empty($almacenDestino)) {
				$this->db->insert('almacenes_productos', [
					'id_producto' => $idProducto,
					'id_almacen' => $traspaso['id_destino'],
					'stock' => $recibido,
					'disponibles' => $recibido,
					'reservados' => 0,
					'en_transito' => 0
				]);

				$reservadosDestino  = 0;
				$disponiblesDestino = $recibido;
			} else {
				$this->db->where('id', $almacenDestino['id']);
				$this->db->update('almacenes_productos', [
					'stock' => $almacenDestino['stock'] + $recibido,
					'disponibles' => $almacenDestino['disponibles'] + $recibido
				]);

				$reservadosDestino  = (int)$almacenDestino['reservados'];
				$disponiblesDestino = (int)$almacenDestino['disponibles'] + $recibido;
			}

			// Después de actualizar $almacenDestino dentro del foreach
			if (!isset($this->Quiebre)) {
				$this->load->model('Quiebre_model', 'Quiebre');
			}
			// Cierra quiebre de tipo 'sucursal' en el almacén destino
			$this->Quiebre->cerrar_quiebre_sucursal($idProducto, $traspaso['id_destino']);

			// Registro estado final //
			$this->db->where('id', $idPT);
			$this->db->update('productos_traspasos', [
				'reservados_origen'   => $reservadosOrigen,
				'disponibles_origen'  => $nuevosDispOrigen,
				'reservados_destino'  => $reservadosDestino,
				'disponibles_destino' => $disponiblesDestino,
				'impacto_stock'       => 1
			]);

			$idProductos[] = $idProducto;
		}

		// Ajuste stock global //
		$this->load->model('Producto_model', 'Producto');
		$this->Producto->ajusta_stock_ps($idProductos);

		if ($this->db->trans_status() === FALSE || !empty($data['errores'])) {
			$this->db->trans_rollback();
			return [
				'status' => 'error',
				'message' => !empty($data['errores']) ? implode('<br>', $data['errores']) : 'Error en transacción'
			];
		}

		$this->db->trans_commit();
		return ['status' => 'success'];
	}


	/********************************* Utilidades Edición ****************************************/


	private function validar($data) {
		$result['status'] = 'success';

		if (in_array($data['estado_traspaso'], [0, 1])) {
			if (empty($data['descripcion'])) {
				$result['status'] = 'error';
				$result['errores']['descripcion'] = 'Debes ingresar una descripción.';
			}

			// origen y destino válidos
			if (empty($data['id_origen'])) {
				$result['status'] = 'error';
				$result['errores']['id_origen'] = 'Debes seleccionar un origen válido.';
			}
			if (empty($data['id_destino'])) {
				$result['status'] = 'error';
				$result['errores']['id_destino'] = 'Debes seleccionar un destino válido.';
			}

			if (!empty($data['id_producto'])) {
				// Validar que vengan datos en productos
				$encontrados = 0;
				foreach ($data['id_producto'] as $key => $idProducto) {
					if (!empty($idProducto)) {
						$encontrados++;
						if (empty($data['solicitado'][$key])) {
							// Para nuevos traspasos se valida que todos los productos tengan cantidad solicitada
							if (empty($data['estado_traspaso'])) {
								$result['status'] = 'error';
								$result['errores']['solicitado'] = 'Debes ingresar el número solicitado de todos los productos.';
							}
						}
					}
				}
				if (!$encontrados) {
					$result['status'] = 'error';
					$result['errores']['id_producto'] = 'No hay productos ingresados.';
				}
			}
			else {
				$result['status'] = 'error';
				$result['errores']['id_producto'] = 'No hay productos ingresados.';
			}
		}

		return $result;
	}


	public function cambiar_destino($idTraspaso, $idDestino) {

		$this->db->where('id', $idTraspaso);
		$this->db->where('deleted', 0);

		$traspaso = $this->db->get('traspasos')->row_array();

		if (empty($traspaso)) {

			return [
				'status' => 'error',
				'message' => 'Traspaso no encontrado'
			];
		}

		// No permitir completados ni cancelados
		if (in_array($traspaso['estado_traspaso'], [4, 5])) {

			return [
				'status' => 'error',
				'message' => 'No se puede cambiar el destino de este traspaso'
			];
		}

		// Evitar mismo destino
		if ($traspaso['id_destino'] == $idDestino) {

			return [
				'status' => 'error',
				'message' => 'El destino ya es el seleccionado'
			];
		}

		// Evitar mismo origen y destino
		if ($traspaso['id_origen'] == $idDestino) {

			return [
				'status' => 'error',
				'message' => 'El destino no puede ser igual al origen'
			];
		}

		$this->db->where('id', $idTraspaso);

		$this->db->update('traspasos', [
			'id_destino' => $idDestino
		]);

		return [
			'status' => 'success'
		];
	}
}