<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Inventario_model extends CI_Model
{
	public function __construct()
	{
		parent::__construct();
		$this->crear_tabla_si_no_existe();
	}

	public function obtener_materiales()
	{
		return $this->db
			->select('m.id, m.nombre, m.unidad, m.stock_minimo, m.costo, m.proveedor, m.nota, m.stock_actual, m.parent_id, p.nombre AS parent_nombre')
			->from('inventario_materiales m')
			->join('inventario_materiales p', 'p.id = m.parent_id', 'left')
			->order_by('m.id', 'DESC')
			->get()
			->result();
	}

	public function obtener_productos()
	{
		return $this->db
			->where('cantidad >', 0)
			->order_by('id', 'DESC')
			->get('inventario_productos')
			->result();
	}

	public function crear_material($data)
	{
		$parent_id = isset($data['parent_id']) && (int) $data['parent_id'] > 0 ? (int) $data['parent_id'] : NULL;

		return $this->db->insert('inventario_materiales', array(
			'nombre' => $data['nombre'],
			'parent_id' => $parent_id,
			'unidad' => $data['unidad'],
			'stock_minimo' => $data['stock_minimo'],
			'costo' => $data['costo'],
			'proveedor' => $data['proveedor'],
			'nota' => $data['nota'],
			'stock_actual' => 0
		));
	}

	public function obtener_material_por_id($id)
	{
		return $this->db
			->where('id', (int) $id)
			->limit(1)
			->get('inventario_materiales')
			->row();
	}

	public function obtener_movimientos_stock($material_id, $incluir_hijos = FALSE)
	{
		if (!$this->db->table_exists('compras_materiales')) {
			return array();
		}

		$ids = array((int) $material_id);
		if ($incluir_hijos) {
			$hijos = $this->db
				->select('id')
				->where('parent_id', (int) $material_id)
				->get('inventario_materiales')
				->result();
			foreach ($hijos as $hijo) {
				$ids[] = (int) $hijo->id;
			}
		}

		$ids = array_values(array_unique(array_filter($ids, function ($v) {
			return (int) $v > 0;
		})));

		if (empty($ids)) {
			return array();
		}

		return $this->db
			->select('c.id, c.compra_ref, c.proveedor, c.material_id, c.cantidad, c.costo_unitario, c.creado_en, m.nombre AS material_nombre, m.unidad')
			->from('compras_materiales c')
			->join('inventario_materiales m', 'm.id = c.material_id', 'left')
			->where_in('c.material_id', $ids)
			->order_by('c.id', 'DESC')
			->limit(120)
			->get()
			->result();
	}

	public function actualizar_material($id, $data)
	{
		$parent_id = isset($data['parent_id']) && (int) $data['parent_id'] > 0 ? (int) $data['parent_id'] : NULL;

		return $this->db
			->where('id', (int) $id)
			->update('inventario_materiales', array(
				'nombre' => $data['nombre'],
				'parent_id' => $parent_id,
				'unidad' => $data['unidad'],
				'stock_minimo' => $data['stock_minimo'],
				'costo' => $data['costo'],
				'proveedor' => $data['proveedor'],
				'nota' => $data['nota']
			));
	}

	public function crear_producto($data)
	{
		return $this->db->insert('inventario_productos', array(
			'nombre' => $data['nombre'],
			'cantidad' => $data['cantidad'],
			'precio' => $data['precio']
		));
	}

	public function obtener_producto_por_id($id)
	{
		return $this->db
			->where('id', (int) $id)
			->limit(1)
			->get('inventario_productos')
			->row();
	}

	public function vender_producto($id, $precio_venta)
	{
		$producto = $this->obtener_producto_por_id($id);
		if (!$producto) {
			return array('ok' => FALSE, 'message' => 'El producto no existe.');
		}

		$cantidad_actual = (int) $producto->cantidad;
		if ($cantidad_actual <= 0) {
			return array('ok' => FALSE, 'message' => 'El producto no tiene stock disponible.');
		}

		$this->db->trans_start();
		$this->db->where('id', (int) $id)->update('inventario_productos', array(
			'cantidad' => $cantidad_actual - 1,
			'precio' => (float) $precio_venta
		));
		$venta_data = array(
			'producto_id' => (int) $id,
			'nombre_producto' => (string) $producto->nombre,
			'precio_venta' => (float) $precio_venta,
			'cantidad' => 1
		);
		if ($this->db->field_exists('pedido_id', 'inventario_ventas_productos')) {
			$venta_data['pedido_id'] = (isset($producto->pedido_id) && (int) $producto->pedido_id > 0) ? (int) $producto->pedido_id : NULL;
		}
		$this->db->insert('inventario_ventas_productos', $venta_data);

		if (
			isset($producto->pedido_id) &&
			(int) $producto->pedido_id > 0 &&
			$this->db->table_exists('pedidos') &&
			$this->db->field_exists('estado', 'pedidos')
		) {
			$this->db
				->where('id', (int) $producto->pedido_id)
				->update('pedidos', array('estado' => 'finalizado'));
		}
		$this->db->trans_complete();

		return array(
			'ok' => $this->db->trans_status(),
			'message' => $this->db->trans_status() ? 'Venta registrada correctamente.' : 'No se pudo registrar la venta.'
		);
	}

	public function obtener_fotos_por_pedidos($pedido_ids)
	{
		$ids = array_unique(array_map('intval', (array) $pedido_ids));
		$ids = array_values(array_filter($ids, function ($v) {
			return (int) $v > 0;
		}));
		if (empty($ids)) {
			return array();
		}

		$map = array();

		if ($this->db->table_exists('pedido_fotos')) {
			$rows = $this->db
				->select('pedido_id, foto_path')
				->from('pedido_fotos')
				->where_in('pedido_id', $ids)
				->order_by('id', 'DESC')
				->get()
				->result();

			foreach ($rows as $r) {
				$pid = (int) $r->pedido_id;
				if (!isset($map[$pid])) {
					$map[$pid] = array();
				}
				$path = (string) $r->foto_path;
				if ($path !== '' && !in_array($path, $map[$pid], TRUE)) {
					$map[$pid][] = $path;
				}
			}
		}

		if ($this->db->table_exists('pedidos') && $this->db->field_exists('foto_path', 'pedidos')) {
			$legacy = $this->db
				->select('id, foto_path')
				->from('pedidos')
				->where_in('id', $ids)
				->get()
				->result();

			foreach ($legacy as $r) {
				$pid = (int) $r->id;
				$path = (string) $r->foto_path;
				if ($path === '') {
					continue;
				}
				if (!isset($map[$pid])) {
					$map[$pid] = array();
				}
				if (!in_array($path, $map[$pid], TRUE)) {
					$map[$pid][] = $path;
				}
			}
		}

		return $map;
	}

	public function obtener_categorias()
	{
		return $this->db->query("
			SELECT
				c.id,
				c.nombre,
				c.parent_id,
				p.nombre AS parent_nombre,
				GROUP_CONCAT(DISTINCT m.nombre ORDER BY m.nombre SEPARATOR ', ') AS materiales_template
			FROM inventario_categorias c
			LEFT JOIN inventario_categorias p ON p.id = c.parent_id
			LEFT JOIN inventario_categoria_materiales cm ON cm.categoria_id = c.id
			LEFT JOIN inventario_materiales m ON m.id = cm.material_id
			GROUP BY c.id, c.nombre, c.parent_id, p.nombre
			ORDER BY c.id DESC
		")->result();
	}

	public function obtener_categoria_por_id($id)
	{
		return $this->db
			->where('id', (int) $id)
			->limit(1)
			->get('inventario_categorias')
			->row();
	}

	public function existe_material($id)
	{
		return (bool) $this->db
			->where('id', (int) $id)
			->limit(1)
			->get('inventario_materiales')
			->row();
	}

	public function crear_categoria($nombre, $parent_id, $material_ids = array())
	{
		$parent = ($parent_id > 0) ? (int) $parent_id : NULL;

		$this->db->trans_start();
		$this->db->insert('inventario_categorias', array(
			'nombre' => $nombre,
			'parent_id' => $parent
		));
		$categoria_id = (int) $this->db->insert_id();

		if ($parent !== NULL && !empty($material_ids)) {
			$material_ids = array_unique(array_map('intval', (array) $material_ids));
			foreach ($material_ids as $mat_id) {
				if ($mat_id <= 0) {
					continue;
				}
				$this->db->insert('inventario_categoria_materiales', array(
					'categoria_id' => $categoria_id,
					'material_id' => $mat_id
				));
			}
		}

		$this->db->trans_complete();
		return $this->db->trans_status();
	}

	private function crear_tabla_si_no_existe()
	{
		$sql_materiales = "CREATE TABLE IF NOT EXISTS inventario_materiales (
			id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
			nombre VARCHAR(120) NOT NULL,
			parent_id INT UNSIGNED NULL,
			unidad VARCHAR(30) NOT NULL,
			stock_minimo INT NOT NULL DEFAULT 0,
			stock_actual INT NOT NULL DEFAULT 0,
			costo DECIMAL(10,2) NOT NULL DEFAULT 0.00,
			proveedor VARCHAR(120) NOT NULL,
			nota VARCHAR(500) NULL,
			creado_en TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
			INDEX idx_parent_id (parent_id)
		) ENGINE=InnoDB DEFAULT CHARSET=utf8";

		$sql_productos = "CREATE TABLE IF NOT EXISTS inventario_productos (
			id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
			nombre VARCHAR(120) NOT NULL,
			pedido_id INT UNSIGNED NULL,
			cantidad INT NOT NULL DEFAULT 0,
			precio DECIMAL(10,2) NOT NULL DEFAULT 0.00,
			creado_en TIMESTAMP DEFAULT CURRENT_TIMESTAMP
		) ENGINE=InnoDB DEFAULT CHARSET=utf8";

		$sql_categorias = "CREATE TABLE IF NOT EXISTS inventario_categorias (
			id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
			nombre VARCHAR(120) NOT NULL,
			parent_id INT UNSIGNED NULL,
			creado_en TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
			INDEX idx_parent_id (parent_id)
		) ENGINE=InnoDB DEFAULT CHARSET=utf8";

		$sql_categorias_materiales = "CREATE TABLE IF NOT EXISTS inventario_categoria_materiales (
			id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
			categoria_id INT UNSIGNED NOT NULL,
			material_id INT UNSIGNED NOT NULL,
			UNIQUE KEY uniq_categoria_material (categoria_id, material_id),
			INDEX idx_categoria_id (categoria_id),
			INDEX idx_material_id (material_id)
		) ENGINE=InnoDB DEFAULT CHARSET=utf8";

		$sql_ventas_productos = "CREATE TABLE IF NOT EXISTS inventario_ventas_productos (
			id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
			producto_id INT UNSIGNED NOT NULL,
			pedido_id INT UNSIGNED NULL,
			nombre_producto VARCHAR(120) NOT NULL,
			precio_venta DECIMAL(10,2) NOT NULL DEFAULT 0.00,
			cantidad INT NOT NULL DEFAULT 1,
			creado_en TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
			INDEX idx_producto_id (producto_id),
			INDEX idx_pedido_id (pedido_id)
		) ENGINE=InnoDB DEFAULT CHARSET=utf8";

		$this->db->query($sql_materiales);
		$this->db->query($sql_productos);
		$this->db->query($sql_categorias);
		$this->db->query($sql_categorias_materiales);
		$this->db->query($sql_ventas_productos);

		$this->asegurar_estructura_materiales();
	}

	private function asegurar_estructura_materiales()
	{
		if (!$this->db->field_exists('unidad', 'inventario_materiales')) {
			$this->db->query("ALTER TABLE inventario_materiales ADD COLUMN unidad VARCHAR(30) NOT NULL DEFAULT 'unidad'");
		}
		if (!$this->db->field_exists('parent_id', 'inventario_materiales')) {
			$this->db->query("ALTER TABLE inventario_materiales ADD COLUMN parent_id INT UNSIGNED NULL");
		}
		if (!$this->db->field_exists('stock_minimo', 'inventario_materiales')) {
			$this->db->query("ALTER TABLE inventario_materiales ADD COLUMN stock_minimo INT NOT NULL DEFAULT 0");
		}
		if (!$this->db->field_exists('costo', 'inventario_materiales')) {
			$this->db->query("ALTER TABLE inventario_materiales ADD COLUMN costo DECIMAL(10,2) NOT NULL DEFAULT 0.00");
		}
		if (!$this->db->field_exists('stock_actual', 'inventario_materiales')) {
			$this->db->query("ALTER TABLE inventario_materiales ADD COLUMN stock_actual INT NOT NULL DEFAULT 0");
		}
		if (!$this->db->field_exists('proveedor', 'inventario_materiales')) {
			$this->db->query("ALTER TABLE inventario_materiales ADD COLUMN proveedor VARCHAR(120) NOT NULL DEFAULT 'Sin proveedor'");
		}
		if (!$this->db->field_exists('nota', 'inventario_materiales')) {
			$this->db->query("ALTER TABLE inventario_materiales ADD COLUMN nota VARCHAR(500) NULL");
		}
		if ($this->db->table_exists('inventario_productos') && !$this->db->field_exists('pedido_id', 'inventario_productos')) {
			$this->db->query("ALTER TABLE inventario_productos ADD COLUMN pedido_id INT UNSIGNED NULL");
		}
		if ($this->db->table_exists('inventario_ventas_productos') && !$this->db->field_exists('pedido_id', 'inventario_ventas_productos')) {
			$this->db->query("ALTER TABLE inventario_ventas_productos ADD COLUMN pedido_id INT UNSIGNED NULL");
		}
	}
}
