<?php

class Almacen_model extends CI_Model {

	/* Funciones de Consulta */
	public function lista($activos = true) {
		$this->db->select('id, nombre');
		$this->db->from('almacenes');
		$this->db->where('deleted', 0);

		if ($activos) {
			$this->db->where('activo', 1);
		}

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

		$almacenes = $this->db->get()->result_array();

		$r = [];
		foreach ($almacenes as $a) {
			$r[$a['id']] = $a['nombre'];
		}

		return $r;
	}

	/**
	 * Entrega listado de todos los almacenes existentes con todas sus propiedades
	 */
	public function listado() {
		$this->db->select('*');
		$this->db->from('almacenes');
		$this->db->where('deleted', 0);
		$this->db->order_by('id', 'ASC');
		$almacenes = $this->db->get()->result_array();
		return $almacenes;
	}


	/**
	 * Entrega listado de almacenes tienda
	 */
	public function tiendas($activos = true) {
		$this->db->select('id, nombre');
		$this->db->from('almacenes');
		$this->db->where('tipo', 2);
		$this->db->where('deleted', 0);

		if ($activos) {
			$this->db->where('activo', 1);
		}

		$this->db->order_by('nombre', 'ASC');

		$almacenes = $this->db->get()->result_array();

		$r = [];
		foreach ($almacenes as $a) {
			$r[$a['id']] = $a['nombre'];
		}

		return $r;
	}


	public function listado_stock() {
		$this->db->select('*');
		$this->db->from('almacenes');
		$this->db->where('deleted', 0);
		$this->db->order_by('id', 'ASC');
		$result = $this->db->get()->result_array();

		$almacenes = [];
		foreach($result as $a) {
			if ($a['activo']) {
				// Tienda
				if ($a['tipo'] == 2){
					$almacenes['tiendas'][$a['id']] = $a['nombre'];
				}
				else if (in_array($a['tipo'], [1, 4, 6])) {
					$almacenes['otros'][$a['id']] = $a['nombre'];
				}
			}
		}
		return $almacenes;
	}


	/*
	 * Entrega stock de productos en cada almacen
	 * TO DO: filtrar por id producto
	 */
	public function stock_productos($idProducto = 0) {
		// Normalizar IDs
		$ids = [];
		if (!empty($idProducto)) {
			if (is_array($idProducto)) {
				$ids = $idProducto;
			} elseif (strpos($idProducto, ',') !== false) {
				$ids = array_filter(array_map('trim', explode(',', $idProducto)));
			} else {
				$ids = [$idProducto];
			}
		}

		// Productos
		$this->db->select('id, nombre');
		$this->db->from('productos');
		$this->db->where('deleted', 0);
		if (!empty($ids)) {
			$this->db->where_in('id', $ids);
		}
		$this->db->order_by('id', 'ASC');
		$productosDB = $this->db->get()->result_array();
		if (empty($productosDB)) return [];

		$productos = [];
		foreach ($productosDB as $p) {
			$productos[$p['id']] = $p;
		}

		// Almacenes
		$this->db->select('id, nombre, stock_online');
		$this->db->from('almacenes');
		$this->db->where('deleted', 0);
		$this->db->order_by('id', 'ASC');
		$almacenesDB = $this->db->get()->result_array();
		$almacenes = [];
		foreach ($almacenesDB as $a) $almacenes[$a['id']] = $a;

		// Almacenes_productos
		$this->db->from('almacenes_productos');
		$this->db->where('deleted', 0);
		if (!empty($ids)) $this->db->where_in('id_producto', $ids);
		$almacenesProductos = $this->db->get()->result_array();

		$apl = [];
		foreach ($almacenesProductos as $ap) {
			$apl[$ap['id_producto']][$ap['id_almacen']] = [
				'stock' => (int)$ap['stock'],
				'disponibles' => (int)$ap['disponibles'],
				'reservados' => (int)$ap['reservados']
			];
		}

		// Reservados
		$reservados = $this->Producto->reservados_almacenes($ids) ?? [];

		$stocks = [];
		foreach ($productos as $idP => $p) {
			$online = 0;
			foreach ($almacenes as $idA => $a) {
				$base = $apl[$idP][$idA] ?? [
					'stock' => 0,
					'disponibles' => 0,
					'reservados' => 0
				];

				if (!isset($apl[$idP][$idA]) && isset($reservados[$idP][$idA])) {
					$r = (int)$reservados[$idP][$idA];
					$base['disponibles'] = 0 - $r;
					$base['reservados'] = $r;
				}

				$stocks[$idP][$idA] = $base;

				if ($a['stock_online']) $online += $base['disponibles'];
			}

			$stocks[$idP]['online']['disponibles'] = $online;
		}

		return $stocks;
	}

	/**
	 * Entrega listado de productos en que la suma de sus stocks es distinto al seteado en el producto
	 */
	public function descuadres() {
		$this->db->select('p.id, p.ps_id, p.nombre, p.stock, p.id_categoria, SUM(COALESCE(ap.stock,0)) as stock_almacenes');
		$this->db->from('productos p');
		$this->db->join('almacenes_productos ap','p.id = ap.id_producto AND ap.deleted = 0', 'left');
		$this->db->where('p.deleted', 0);
		$this->db->group_by('p.id');
		$this->db->having('SUM(COALESCE(ap.stock, 0)) != p.stock');
		$this->db->order_by('id_categoria ASC, (p.stock - SUM(COALESCE(ap.stock,0))) DESC');
		$descuadres = $this->db->get()->result_array();

		$return = [];
		foreach($descuadres as $descuadre) {
			$return[$descuadre['id_categoria']][] = $descuadre;
		}

		return $return;
	}

	public function monitor($idAlmacen = 2, $filtros = []) {
		$this->db->select('p.id, p.ps_id, p.nombre, p.costo, p.disponibles, p.id_proveedor, p.id_categoria, ap.id as id_almacen_producto, ap.id_almacen, COALESCE(ap.disponibles,0) as disponibles_almacen, COALESCE(ap.deseados,0) as deseados_almacen, COALESCE(ap.deseados_max,0) as deseados_max_almacen, ap.stock, ap.reservados, ap.fecha_revision, ap.id_revisor, ap.error');
		$this->db->from('productos p');
		$this->db->join('almacenes_productos ap','p.id = ap.id_producto AND ap.id_almacen = ' . $idAlmacen . ' AND ap.deleted = 0', 'left');
		$this->db->where('p.deleted', 0);
		// Tipo 6 = Requeridos
		// Para tipo 6 se ignora si está agotado, pues se debe traspasar
		if ($filtros['tipo'] != 6) {
			//Comentamos para ver si genera errores (04/07/2024)
			//$this->db->where('p.disponibles >', 0);
		}

		// Bodega: considera ventas en web, mercado libre, falabella y otros
		$idCanal = [0];
		if ($idAlmacen == 1) {
			$idCanal = [1, 3, 5, 6];
		}
		// Tienda: Solo considera ventas en tienda
		if ($idAlmacen == 2) {
			$idCanal = [2];
		}

		// Feria: Solo considera ventas en feria
		if ($idAlmacen == 3) {
			$idCanal = [4];
		}

		// Tienda Italia 1601: Solo considera ventas en tienda
		if ($idAlmacen == 5) {
			$idCanal = [7];
		}

		// Tipo 0 = bloquea para no cargar productos
		if ($filtros['tipo'] === "0") {
			$this->db->where('p.id', 0);
		}

		// Tipo 1 = En Existencia
		if ($filtros['tipo'] == 1) {
			//$this->db->where('ap.id_almacen', $idAlmacen);
			$this->db->where('ap.stock >', 0);
			$this->db->where('ap.deleted', 0);
		}

		// Tipo 2: Faltantes
		if ($filtros['tipo'] == 2) {
			// Se agrega condición de que no muestre Insumos, Demos ni Virtuales
			$categoriasIgnoradas = [7, 10, 11, 12];
			if (!in_array($filtros['categoria'], $categoriasIgnoradas)) {
				$this->db->where_not_in('id_categoria', $categoriasIgnoradas);
			}

			$this->db->group_start();
				$this->db->where('ap.id_almacen', $idAlmacen);
				$this->db->or_where('ap.id_almacen IS NULL');
			$this->db->group_end();

			$this->db->group_start();
				$this->db->where('ap.disponibles <', 1);
				$this->db->or_where('ap.disponibles IS NULL');
			$this->db->group_end();

			$this->db->group_start();
				$this->db->where('ap.deleted', 0);
				$this->db->or_where('ap.id IS NULL');
			$this->db->group_end();

			$this->db->group_start();
				$this->db->where('ap.deseados >=', 0);
				$this->db->or_where('ap.deseados IS NULL');
			$this->db->group_end();

			$this->db->where('p.disponibles >', 0);
		}

		// Tipo 3: Deseados
		if ($filtros['tipo'] == 3) {
			$this->db->where('ap.disponibles < ap.deseados');
			$this->db->where('p.disponibles > ap.disponibles');
			$this->db->where('p.disponibles > 0');
			$this->db->where('ap.deleted', 0);
		}

		// Tipo 4: Sugeridos
		if ($filtros['tipo'] == 4) {

			$this->db->select('SUM(pv.cantidad) as vendidos_quincena');
			// left join productos_ventas pv ON p.id = pv.id_producto
			$this->db->join('productos_ventas pv','p.id = pv.id_producto', 'left');
			// left join ventas v ON v.id = pv.id_venta
			$this->db->join('ventas v','pv.id_venta = v.id', 'left');
			//and v.fecha_venta BETWEEN CURDATE() - INTERVAL 15 DAY AND CURDATE()
			$this->db->where('DATE_FORMAT(v.fecha_venta, "%Y-%m-%d") BETWEEN CURDATE() - INTERVAL 15 DAY AND CURDATE()');
			// Solo ventas en tienda
			$this->db->where_in('v.id_canal', $idCanal);
			// Solo productos que no sean indeseados
			$this->db->where('ap.deseados >=', 0);
			$this->db->where('p.disponibles > ap.disponibles');
			$this->db->where('pv.deleted', 0);
			$this->db->where('v.deleted', 0);

			$this->db->group_by('pv.id_producto');
			// Solo productos que se haya vendido más de 1
			$this->db->having('vendidos_quincena >', 1);
			$this->db->having('disponibles_almacen <', 'vendidos_quincena', false);
			$this->db->order_by('vendidos_quincena', 'DESC');
		}

		// Tipo 5: No deseados
		if ($filtros['tipo'] == 5) {
			$this->db->where('ap.deseados', '-1');
			$this->db->where('ap.deleted', 0);
		}

		// Tipo 6: Requeridos
		if ($filtros['tipo'] == 6) {
			$this->db->where('ap.disponibles < 0');
			$this->db->where('ap.deleted', 0);
		}

		// Existente busca productos que no tengan stock negativo
		if (!empty($filtros['existente'])) {
			$this->db->where('p.disponibles >=', 0);
		}

		if (!empty($filtros['categoria'])) {
			$this->db->where('p.id_categoria', $filtros['categoria']);
		}
		else {
			// Solo excluir insumos si NO es inventario
			if (empty($filtros['modo_inventario'])) {
				$this->db->where('p.id_categoria !=', 7);
			}
		}
		if (!empty($filtros['proveedor'])) {
			$this->db->where('p.id_proveedor', $filtros['proveedor']);
		}

		if (!empty($filtros['id_ubicacion'])) {
			if ($filtros['id_ubicacion'] == '-1') {
				$this->db->where('ap.id_ubicacion', 0);
			}
			else {
				$this->db->where('ap.id_ubicacion', $filtros['id_ubicacion']);
			}
		}

		//$this->db->order_by('id_categoria ASC, p.disponibles DESC');
		//Se cambia a solo ordenar por disponibles (04/07/2024)
		if ($filtros['tipo'] != 4) {
			if (empty($filtros['orden'])) {
				$this->db->order_by('p.disponibles DESC');
			}
			if (!empty($filtros['orden'])) {
				if ($filtros['orden'] == 1) {
					$this->db->order_by('ap.disponibles DESC');
				}
				if ($filtros['orden'] == 2) {
					$this->db->order_by('ap.fecha_revision ASC');
				}
				if ($filtros['orden'] == 3) {
					$this->db->order_by('p.nombre ASC');
				}
			}
		}

		// MODO INVENTARIO
		if (!empty($filtros['modo_inventario'])) {
			// Excluir virtuales (ajusta según tu categoría real)
			$categoriasVirtuales = [11];

			$this->db->where_not_in('p.id_categoria', $categoriasVirtuales);
		}

		$faltantes = $this->db->get()->result_array();
		if (empty($faltantes)) {
			return [];
		}

		// Recolectar todos los IDs
		$ids = array_column($faltantes, 'id');
		// Llamada única a stock_productos con array de IDs
		$stocksTodos = $this->stock_productos($ids);

		// Asignar stocks a cada producto
		foreach ($faltantes as &$p) {
			$p['stocks'] = $stocksTodos[$p['id']] ?? [];
		}

		return $faltantes;
	}


	public function errores_inventario($filtros = []) {
		$this->db->select('i.*, p.nombre, p.ps_id');
		$this->db->from('inventarios i');
		$this->db->join('productos p','i.id_producto = p.id', 'left');
		$this->db->where('i.error', 1);
		$this->db->where('i.deleted', 0);
		$this->db->where('p.deleted', 0);
		
		if (!empty($filtros['corregido'])) {
			$this->db->where('i.corregido', 1);
			$this->db->order_by('i.fecha_correccion', 'DESC');
		}
		else {
			$this->db->where('i.corregido', 0);
			$this->db->order_by('i.fecha_revision', 'ASC');
		}
		


		$inventarios = $this->db->get()->result_array();

		return $inventarios;
	}

	public function inventarios($filtros = []) {
		$this->db->select('i.*, DATE_FORMAT(i.created, "%Y%m%d") as fecha, DATE_FORMAT(i.created, "%Y%m") as periodo, p.nombre, p.ps_id');
		$this->db->from('inventarios i');
		$this->db->join('productos p','i.id_producto = p.id', 'left');
		$this->db->where('i.deleted', 0);
		$this->db->where('p.deleted', 0);
		
		if (!empty($filtros['id_almacen'])) {
			$this->db->where('i.id_almacen', $filtros['id_almacen']);
		}
		if (!empty($filtros['id_revisor'])) {
			$this->db->where('i.id_revisor', $filtros['id_revisor']);
		}
		if (!empty($filtros['fecha'])) {
			// Comparar solo la fecha sin la hora
			$this->db->where('DATE(i.created)', $filtros['fecha']);
		}

		$this->db->order_by('i.fecha_revision', 'DESC');

		$inventarios = $this->db->get()->result_array();

		$res = [];

		foreach ($inventarios as $i) {
			$res[$i['fecha']][] = $i;
		}

		return $res;
	}

	public function periodos_inventarios($filtros = []) {
		$this->db->select('DISTINCT(DATE_FORMAT(i.created, "%Y%m")) as periodo');
		$this->db->from('inventarios i');
		$this->db->where('i.deleted', 0);
		
		if (!empty($filtros['id_almacen'])) {
			$this->db->where('i.id_almacen', $filtros['id_almacen']);
		}

		$this->db->order_by('i.fecha_revision', 'DESC');

		$inventarios = $this->db->get()->result_array();

		$res[date('Ym')] = date('Ym');

		foreach ($inventarios as $i) {
			$res[$i['periodo']] = $i['periodo'];
		}

		return $res;
	}


	/**
	 * Busca todos los productos sin registro en un almacen y le carga registro con cantidades en 0
	 */
	public function carga_vacios() {
		$this->db->select('id');
		$this->db->from('productos');
		$this->db->where('deleted', 0);
		$productos = $this->db->get()->result_array();

		$this->db->select('id');
		$this->db->from('almacenes');
		$this->db->where('deleted', 0);
		$almacenes = $this->db->get()->result_array();

		$this->db->select('id, id_almacen, id_producto');
		$this->db->from('almacenes_productos');
		$this->db->where('deleted', 0);
		$almacenesProductos = $this->db->get()->result_array();

		foreach($almacenesProductos as $ap) {
			$AxP[$ap['id_almacen']][$ap['id_producto']] = $ap['id'];
		}

		foreach($almacenes as $a) {
			foreach($productos as $p) {
				if (empty($AxP[$a['id']][$p['id']])) {
					pr('Insertando Producto ' . $p['id'] . ' en almacén ' . $a['id']);
					$new_ap = [
						'id_almacen' => $a['id'],
						'id_producto' => $p['id'],
						'stock' => 0,
						'disponibles' => 0,
						'reservados' => 0
					];
					$this->db->insert('almacenes_productos', $new_ap);
				}
			}
		}
	}

    /**
     * Entrega Stock online de un producto
     */
	public function stock_online($id) {
		if (!empty($id)) {
			$this->db->select("
				p.id,
				SUM(
					CASE 
						WHEN a.stock_online = 1 THEN ap.disponibles
						ELSE 
							CASE 
								WHEN ap.disponibles < 0 THEN ap.disponibles
								ELSE 0
							END
					END
				) as stock_online
			", false);
			$this->db->from('productos p');
			$this->db->join('almacenes_productos ap', 'p.id = ap.id_producto', 'left');
			$this->db->join('almacenes a', 'ap.id_almacen = a.id', 'left');
			$this->db->where('p.id', $id);
			$this->db->where('p.deleted', 0);
			$this->db->where('ap.deleted', 0);
			$this->db->where('a.deleted', 0);
			$this->db->where('p.ignora_descuadre', 0);
			$this->db->group_by('p.id');

			$row = $this->db->get()->row_array();

			return !empty($row) ? (int)$row['stock_online'] : 0;
		}
		return 0;
	}

	/**
	 * Entrega la información de un almacén Producto según id
	 */
	public function get_almacen_producto($id) {
		if (!empty($id)) {
			$this->db->select('ap.*, p.nombre as nombre_producto, a.nombre as nombre_almacen, u.alias as nombre_revisor');
			$this->db->from('almacenes_productos ap');
			$this->db->join('productos p', 'ap.id_producto = p.id', 'left');
			$this->db->join('almacenes a', 'ap.id_almacen = a.id', 'left');
			$this->db->join('usuarios u', 'ap.id_revisor = u.id', 'left');
			$this->db->where('ap.id', $id);
			$this->db->where('ap.deleted', 0);
			$this->db->where('p.deleted', 0);
			$this->db->where('a.deleted', 0);
			return $this->db->get()->row_array();
		}
		return [];
	}

	/**
	 * Entrega lista de almacenes con sus ubicaciones
	 */
	public function ubicaciones() {
		$this->db->select('id, id_almacen, nombre');
		$this->db->from('ubicaciones');
		$this->db->where('deleted', 0);

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

		$ubicaciones = $this->db->get()->result_array();

		$r = [];
		foreach ($ubicaciones as $u) {
			$r[$u['id_almacen']][$u['id']] = $u['nombre'];
		}
		return $r;
	}

	/**
	 * Entrega info de una ubicacion
	 */
	public function get_ubicacion($id) {
		$this->db->select('id, id_almacen, nombre');
		$this->db->from('ubicaciones');
		$this->db->where('deleted', 0);
		$this->db->where('id', $id);

		return $this->db->get()->row_array();
	}

	/**
	 * Crea o edita la info de una ubicacion
	 */
	public function save_ubicacion($data) {
		//revisar si viene id y si viene se hace update
		if (empty($data['id'])) {
			$this->db->insert('ubicaciones', $data);
			return $this->db->insert_id();
		}
		else {
			$this->db->where('id', $data['id']);
			$this->db->update('ubicaciones', $data);
			return $data['id'];
		}
	}


	/**
	 * Entrega info de un inventario
	 */
	public function get_inventario($id) {
		$this->db->select('i.*, p.nombre as nombre_producto, a.nombre as nombre_almacen');
		$this->db->from('inventarios i');
		$this->db->join('productos p','i.id_producto = p.id', 'left');
		$this->db->join('almacenes a','i.id_almacen = a.id', 'left');
		$this->db->where('i.deleted', 0);
		$this->db->where('i.id', $id);

		return $this->db->get()->row_array();
	}

	/**
	 * Guarda info de un inventario
	 */
	public function save_inventario($data) {
		//prx($data);
		$this->db->from('inventarios i');
		$this->db->where('i.deleted', 0);
		$this->db->where('i.id', $data['id']);
		$inventario = $this->db->get()->row_array();

		$this->db->from('almacenes_productos');
		$this->db->where('id_almacen', $inventario['id_almacen']);
		$this->db->where('id_producto', $inventario['id_producto']);
		$this->db->where('deleted', 0);

		$almacenProducto = $this->db->get()->row_array();

		$fecha = date('Y-m-d H:i:s');

		$newAP = [
			'error' => 0,
			'id_revisor' => $_SESSION['usuario']['id'],
			'fecha_revision' => $fecha
		];

		$this->db->where('id', $almacenProducto['id']);
		$this->db->update('almacenes_productos', $newAP);

		$newInventario = [
			'corregido' => 1,
			'id_corrector' => $_SESSION['usuario']['id'],
			'fecha_correccion' => $fecha,
			'accion_correccion' => $data['accion_correccion']
		];

		$this->db->where('id', $data['id']);
		$this->db->update('inventarios', $newInventario);
		return $data['id'];		
	}


	/**
	 * Valida stock en Ap y crea registro en inventario
	 */
	public function save_validar_stock($data) {
		$this->db->from('almacenes_productos ap');
		$this->db->where('ap.id', $data['id']);
		$this->db->where('ap.deleted', 0);
		$almacenProducto = $this->db->get()->row_array();

		$fechaRevision = date('Y-m-d H:i:s');

		$inventario = [
			'id_producto' => $almacenProducto['id_producto'],
			'id_almacen' => $almacenProducto['id_almacen'],
			'id_revisor' => $_SESSION['usuario']['id'],
			'fecha_revision' => $fechaRevision,
			'stock_sistema' => $almacenProducto['stock'],
			'stock_encontrado' =>  $data['stock_encontrado'],
			'error' => 0
		];

		$newAP = [
			'id_revisor' => $_SESSION['usuario']['id'],
			'fecha_revision' => $fechaRevision
		];

		if ($almacenProducto['stock'] != $data['stock_encontrado']) {
			$inventario['error'] =  1;
			$newAP['error'] = 1;
		}

		/*
		if ($data['status'] != 'ok') {
			$inventario['stock_encontrado'] =  $data['stock_encontrado'];
			$inventario['error'] =  1;
			$newAP['error'] = 1;
		}
		*/
		// Guardar Inventario
		$this->db->insert('inventarios', $inventario);

		// guardar revisión en AP
		$newAP['id_revisor'] = $_SESSION['usuario']['id'];
		$newAP['fecha_revision'] = $fechaRevision;
		$this->db->where('id', $data['id']);
		$this->db->update('almacenes_productos', $newAP);
		return $inventario;
	}


	public function count_errores() {
		if (!empty($_SESSION['usuario'])) {

			$this->db->select('i.id');
			$this->db->from('inventarios i');
			$this->db->where('i.error', 1);
			$this->db->where('i.deleted', 0);
			$this->db->where('i.corregido', 0);
			$this->db->order_by('i.created', 'ASC');
			$inventarios = $this->db->get()->result_array();

			$_SESSION['errores_inventario'] = count($inventarios);
		}
	}

	/*
	 * Entrega total de costo y de pvp por almacen y filtros
	**/
	public function totales_inventario($idAlmacen, $filtros = []) {

		$this->db->select('
			SUM(COALESCE(ap.stock,0)) as total_unidades,

			SUM(COALESCE(ap.stock,0) * p.costo) as total_costo,

			SUM(
				COALESCE(ap.stock,0) * 
				(CASE 
					WHEN p.precio_oferta > 0 THEN p.precio_oferta 
					ELSE p.precio 
				END)
			) as total_venta
		');

		$this->db->from('productos p');
		$this->db->join('almacenes_productos ap',
			'p.id = ap.id_producto AND ap.id_almacen = ' . $idAlmacen . ' AND ap.deleted = 0',
			'left'
		);

		$this->db->where('p.deleted', 0);

		// Excluye virtuales
		$this->db->where_not_in('p.id_categoria', [11]);

		// mismo criterio que usas en inventario (tipo 1 = con stock)
		if (!empty($filtros['tipo']) && $filtros['tipo'] == 1) {
			$this->db->where('ap.stock >', 0);
		}

		// filtros opcionales
		if (!empty($filtros['categoria'])) {
			$this->db->where('p.id_categoria', $filtros['categoria']);
		}

		if (!empty($filtros['id_ubicacion'])) {
			if ($filtros['id_ubicacion'] == '-1') {
				$this->db->where('ap.id_ubicacion', 0);
			} else {
				$this->db->where('ap.id_ubicacion', $filtros['id_ubicacion']);
			}
		}

		return $this->db->get()->row_array();
	}
}