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

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

	public function obtener_clientes()
	{
		if (!$this->db->table_exists('clientes')) {
			return array();
		}

		return $this->db
			->select('id, nombre, telefono')
			->order_by('nombre', 'ASC')
			->get('clientes')
			->result();
	}

	public function obtener_templates_pedido()
	{
		if (
			!$this->db->table_exists('inventario_categorias') ||
			!$this->db->table_exists('inventario_categoria_materiales') ||
			!$this->db->table_exists('inventario_materiales')
		) {
			return array();
		}

		$templates = $this->db->query("
			SELECT
				c.id,
				c.nombre,
				c.parent_id,
				p.nombre AS parent_nombre,
				COUNT(m.id) AS materiales_count,
				COALESCE(SUM(m.costo), 0) AS costo_material_base
			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
			WHERE c.parent_id IS NOT NULL
			GROUP BY c.id, c.nombre, c.parent_id, p.nombre
			ORDER BY c.nombre ASC
		")->result();

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

		$template_ids = array();
		foreach ($templates as $t) {
			$template_ids[] = (int) $t->id;
		}

		$materiales = $this->db
			->select('cm.categoria_id AS template_id, m.id AS material_id, m.nombre, m.unidad, m.costo')
			->from('inventario_categoria_materiales cm')
			->join('inventario_materiales m', 'm.id = cm.material_id', 'inner')
			->where_in('cm.categoria_id', $template_ids)
			->order_by('m.nombre', 'ASC')
			->get()
			->result();

		$map = array();
		foreach ($materiales as $m) {
			$tid = (int) $m->template_id;
			if (!isset($map[$tid])) {
				$map[$tid] = array();
			}
			$map[$tid][] = $m;
		}

		foreach ($templates as $t) {
			$tid = (int) $t->id;
			$t->materiales = isset($map[$tid]) ? $map[$tid] : array();
		}

		return $templates;
	}

	public function obtener_materiales_catalogo()
	{
		if (!$this->db->table_exists('inventario_materiales')) {
			return array();
		}

		return $this->db
			->select('id, nombre, unidad, costo, stock_actual, proveedor')
			->from('inventario_materiales')
			->where('parent_id IS NOT NULL', NULL, FALSE)
			->order_by('nombre', 'ASC')
			->get()
			->result();
	}

	public function obtener_template_por_id($template_id)
	{
		$template_id = (int) $template_id;
		if ($template_id <= 0) {
			return NULL;
		}

		$templates = $this->obtener_templates_pedido();
		foreach ($templates as $t) {
			if ((int) $t->id === $template_id) {
				return $t;
			}
		}

		return NULL;
	}

	public function guardar_pedido($pedido, $lineas)
	{
		$this->db->trans_start();

		$this->db->insert('pedidos', $pedido);
		$pedido_id = (int) $this->db->insert_id();

		foreach ($lineas as $linea) {
			$linea['pedido_id'] = $pedido_id;
			$this->db->insert('pedido_materiales', $linea);
		}

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

	public function obtener_pedido_por_id($pedido_id)
	{
		$pedido = $this->db
			->where('id', (int) $pedido_id)
			->limit(1)
			->get('pedidos')
			->row();
		if (!$pedido) {
			return NULL;
		}

		$lineas = $this->db
			->select('pm.*, m.nombre AS material_nombre, m.unidad')
			->from('pedido_materiales pm')
			->join('inventario_materiales m', 'm.id = pm.material_id', 'left')
			->where('pm.pedido_id', (int) $pedido_id)
			->order_by('pm.id', 'ASC')
			->get()
			->result();

		$fotos = $this->obtener_fotos_por_pedido_id($pedido_id);

		return array(
			'pedido' => $pedido,
			'lineas' => $lineas,
			'fotos' => $fotos
		);
	}

	public function actualizar_pedido($pedido_id, $pedido, $lineas)
	{
		$this->db->trans_start();
		$this->db->where('id', (int) $pedido_id)->update('pedidos', $pedido);
		$this->db->where('pedido_id', (int) $pedido_id)->delete('pedido_materiales');
		foreach ($lineas as $linea) {
			$linea['pedido_id'] = (int) $pedido_id;
			$this->db->insert('pedido_materiales', $linea);
		}
		$this->db->trans_complete();
		return $this->db->trans_status();
	}

	public function actualizar_estado($pedido_id, $estado)
	{
		return $this->db
			->where('id', (int) $pedido_id)
			->update('pedidos', array('estado' => (string) $estado));
	}

	public function agregar_pedido_a_productos($pedido_id)
	{
		$data = $this->obtener_pedido_por_id($pedido_id);
		if (!$data) {
			return FALSE;
		}
		if (!$this->db->table_exists('inventario_productos')) {
			$this->db->query("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");
		}
		if (!$this->db->field_exists('pedido_id', 'inventario_productos')) {
			$this->db->query("ALTER TABLE inventario_productos ADD COLUMN pedido_id INT UNSIGNED NULL");
		}

		$pedido = $data['pedido'];
		$nombre = 'Pedido #'.(int) $pedido->id;
		if (!empty($pedido->template_id) && $this->db->table_exists('inventario_categorias')) {
			$t = $this->db->select('nombre')->where('id', (int) $pedido->template_id)->limit(1)->get('inventario_categorias')->row();
			if ($t && !empty($t->nombre)) {
				$nombre = (string) $t->nombre.' (Pedido #'.(int) $pedido->id.')';
			}
		}

		$existente = $this->db
			->where('pedido_id', (int) $pedido_id)
			->limit(1)
			->get('inventario_productos')
			->row();

		if ($existente) {
			return $this->db
				->where('id', (int) $existente->id)
				->update('inventario_productos', array(
					'nombre' => $nombre,
					'pedido_id' => (int) $pedido_id,
					'cantidad' => 1,
					'precio' => (float) $pedido->total
				));
		}

		return $this->db->insert('inventario_productos', array(
			'nombre' => $nombre,
			'pedido_id' => (int) $pedido_id,
			'cantidad' => 1,
			'precio' => (float) $pedido->total
		));
	}

	public function agregar_foto($pedido_id, $foto_path)
	{
		return $this->db->insert('pedido_fotos', array(
			'pedido_id' => (int) $pedido_id,
			'foto_path' => $foto_path
		));
	}

	public function registrar_venta_finalizada($pedido_id)
	{
		$pedido_id = (int) $pedido_id;
		if ($pedido_id <= 0 || !$this->db->table_exists('pedidos')) {
			return FALSE;
		}

		$this->asegurar_tabla_ventas_productos();

		if ($this->db->field_exists('pedido_id', 'inventario_ventas_productos')) {
			$existe = (bool) $this->db
				->where('pedido_id', $pedido_id)
				->limit(1)
				->get('inventario_ventas_productos')
				->row();
			if ($existe) {
				return TRUE;
			}
		}

		$pedido = $this->db
			->select('id, total')
			->from('pedidos')
			->where('id', $pedido_id)
			->limit(1)
			->get()
			->row();

		if (!$pedido) {
			return FALSE;
		}

		$venta = array(
			'producto_id' => 0,
			'nombre_producto' => 'Pedido #'.$pedido_id,
			'precio_venta' => (float) $pedido->total,
			'cantidad' => 1
		);

		if ($this->db->field_exists('pedido_id', 'inventario_ventas_productos')) {
			$venta['pedido_id'] = $pedido_id;
		}

		return $this->db->insert('inventario_ventas_productos', $venta);
	}

	public function obtener_pedidos()
	{
		if (
			!$this->db->table_exists('pedidos') ||
			!$this->db->table_exists('pedido_materiales') ||
			!$this->db->table_exists('clientes') ||
			!$this->db->table_exists('inventario_categorias')
		) {
			return array();
		}

		$rows = $this->db
			->select('p.*, c.nombre AS cliente_nombre, t.nombre AS template_nombre')
			->from('pedidos p')
			->join('clientes c', 'c.id = p.cliente_id', 'left')
			->join('inventario_categorias t', 't.id = p.template_id', 'left')
			->group_start()
				->where('p.estado', 'pendiente')
				->or_where('p.estado IS NULL', NULL, FALSE)
				->or_where("p.estado = ''", NULL, FALSE)
			->group_end()
			->order_by('p.id', 'DESC')
			->limit(80)
			->get()
			->result();

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

		$pedido_ids = array();
		foreach ($rows as $r) {
			$pedido_ids[] = (int) $r->id;
		}

		$lineas_raw = $this->db
			->select('pm.*, m.nombre AS material_nombre, m.unidad')
			->from('pedido_materiales pm')
			->join('inventario_materiales m', 'm.id = pm.material_id', 'left')
			->where_in('pm.pedido_id', $pedido_ids)
			->order_by('pm.id', 'ASC')
			->get()
			->result();

		$lineas_map = array();
		foreach ($lineas_raw as $l) {
			$pid = (int) $l->pedido_id;
			if (!isset($lineas_map[$pid])) {
				$lineas_map[$pid] = array();
			}
			$lineas_map[$pid][] = $l;
		}

		$fotos_map = $this->obtener_fotos_por_pedido_ids($pedido_ids);

		$pedidos = array();
		foreach ($rows as $r) {
			$pid = (int) $r->id;
			$pedidos[] = array(
				'id' => $pid,
				'fecha' => $r->creado_en,
				'cliente_nombre' => $r->cliente_nombre,
				'template_nombre' => $r->template_nombre,
				'cantidad_material' => (float) $r->cantidad_material,
				'horas_trabajo' => (float) $r->horas_trabajo,
				'margen_porcentaje' => (float) $r->margen_porcentaje,
				'costo_materiales' => (float) $r->costo_materiales,
				'costo_mano_obra' => (float) $r->costo_mano_obra,
				'costo_base' => (float) $r->costo_base,
				'margen_monto' => (float) $r->margen_monto,
				'total' => (float) $r->total,
				'estado' => isset($r->estado) ? (string) $r->estado : 'pendiente',
				'foto_path' => isset($r->foto_path) ? (string) $r->foto_path : '',
				'fotos' => isset($fotos_map[$pid]) ? $fotos_map[$pid] : array(),
				'lineas' => isset($lineas_map[$pid]) ? $lineas_map[$pid] : array()
			);
		}

		return $pedidos;
	}

	public function obtener_pedidos_cerrados()
	{
		if (
			!$this->db->table_exists('pedidos') ||
			!$this->db->table_exists('pedido_materiales') ||
			!$this->db->table_exists('clientes') ||
			!$this->db->table_exists('inventario_categorias')
		) {
			return array();
		}

		$rows = $this->db
			->select('p.*, c.nombre AS cliente_nombre, t.nombre AS template_nombre')
			->from('pedidos p')
			->join('clientes c', 'c.id = p.cliente_id', 'left')
			->join('inventario_categorias t', 't.id = p.template_id', 'left')
			->where_in('p.estado', array('producto', 'agregado_producto', 'finalizado'))
			->order_by('p.id', 'DESC')
			->limit(120)
			->get()
			->result();

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

		$pedido_ids = array();
		foreach ($rows as $r) {
			$pedido_ids[] = (int) $r->id;
		}

		$lineas_raw = $this->db
			->select('pm.*, m.nombre AS material_nombre, m.unidad')
			->from('pedido_materiales pm')
			->join('inventario_materiales m', 'm.id = pm.material_id', 'left')
			->where_in('pm.pedido_id', $pedido_ids)
			->order_by('pm.id', 'ASC')
			->get()
			->result();

		$lineas_map = array();
		foreach ($lineas_raw as $l) {
			$pid = (int) $l->pedido_id;
			if (!isset($lineas_map[$pid])) {
				$lineas_map[$pid] = array();
			}
			$lineas_map[$pid][] = $l;
		}

		$fotos_map = $this->obtener_fotos_por_pedido_ids($pedido_ids);

		$pedidos = array();
		foreach ($rows as $r) {
			$pid = (int) $r->id;
			$pedidos[] = array(
				'id' => $pid,
				'fecha' => $r->creado_en,
				'cliente_nombre' => $r->cliente_nombre,
				'template_nombre' => $r->template_nombre,
				'cantidad_material' => (float) $r->cantidad_material,
				'horas_trabajo' => (float) $r->horas_trabajo,
				'margen_porcentaje' => (float) $r->margen_porcentaje,
				'costo_materiales' => (float) $r->costo_materiales,
				'costo_mano_obra' => (float) $r->costo_mano_obra,
				'costo_base' => (float) $r->costo_base,
				'margen_monto' => (float) $r->margen_monto,
				'total' => (float) $r->total,
				'estado' => isset($r->estado) ? (string) $r->estado : 'pendiente',
				'foto_path' => isset($r->foto_path) ? (string) $r->foto_path : '',
				'fotos' => isset($fotos_map[$pid]) ? $fotos_map[$pid] : array(),
				'lineas' => isset($lineas_map[$pid]) ? $lineas_map[$pid] : array()
			);
		}

		return $pedidos;
	}

	public function existe_cliente($cliente_id)
	{
		if (!$this->db->table_exists('clientes')) {
			return FALSE;
		}

		return (bool) $this->db
			->where('id', (int) $cliente_id)
			->limit(1)
			->get('clientes')
			->row();
	}

	public function obtener_costos_por_material_ids($material_ids)
	{
		$ids = array_unique(array_map('intval', (array) $material_ids));
		$ids = array_values(array_filter($ids, function ($v) {
			return (int) $v > 0;
		}));

		if (empty($ids) || !$this->db->table_exists('inventario_materiales')) {
			return array();
		}

		$rows = $this->db
			->select('id, costo')
			->from('inventario_materiales')
			->where_in('id', $ids)
			->get()
			->result();

		$map = array();
		foreach ($rows as $r) {
			$map[(int) $r->id] = (float) $r->costo;
		}

		return $map;
	}

	private function obtener_fotos_por_pedido_id($pedido_id)
	{
		$pedido_id = (int) $pedido_id;
		if ($pedido_id <= 0) {
			return array();
		}

		$fotos = array();
		$paths = array();

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

			foreach ($rows as $r) {
				$path = isset($r->foto_path) ? trim((string) $r->foto_path) : '';
				if ($path === '' || isset($paths[$path])) {
					continue;
				}
				$paths[$path] = TRUE;
				$fotos[] = $r;
			}
		}

		if ($this->db->field_exists('foto_path', 'pedidos')) {
			$legacy = $this->db
				->select('foto_path')
				->from('pedidos')
				->where('id', $pedido_id)
				->limit(1)
				->get()
				->row();

			$legacy_path = ($legacy && isset($legacy->foto_path)) ? trim((string) $legacy->foto_path) : '';
			if ($legacy_path !== '' && !isset($paths[$legacy_path])) {
				$legacy_row = new stdClass();
				$legacy_row->id = 0;
				$legacy_row->pedido_id = $pedido_id;
				$legacy_row->foto_path = $legacy_path;
				$legacy_row->creado_en = NULL;
				$fotos[] = $legacy_row;
			}
		}

		return $fotos;
	}

	private function obtener_fotos_por_pedido_ids($pedido_ids)
	{
		$pedido_ids = array_unique(array_map('intval', (array) $pedido_ids));
		$pedido_ids = array_values(array_filter($pedido_ids, function ($id) {
			return (int) $id > 0;
		}));
		if (empty($pedido_ids)) {
			return array();
		}

		$map = array();
		$paths_map = array();
		foreach ($pedido_ids as $pid) {
			$map[$pid] = array();
			$paths_map[$pid] = array();
		}

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

			foreach ($rows as $r) {
				$pid = (int) $r->pedido_id;
				$path = isset($r->foto_path) ? trim((string) $r->foto_path) : '';
				if ($path === '' || isset($paths_map[$pid][$path])) {
					continue;
				}
				$paths_map[$pid][$path] = TRUE;
				$map[$pid][] = $r;
			}
		}

		if ($this->db->field_exists('foto_path', 'pedidos')) {
			$legacy_rows = $this->db
				->select('id, foto_path')
				->from('pedidos')
				->where_in('id', $pedido_ids)
				->get()
				->result();

			foreach ($legacy_rows as $r) {
				$pid = (int) $r->id;
				$path = isset($r->foto_path) ? trim((string) $r->foto_path) : '';
				if ($path === '' || isset($paths_map[$pid][$path])) {
					continue;
				}
				$paths_map[$pid][$path] = TRUE;
				$legacy_row = new stdClass();
				$legacy_row->id = 0;
				$legacy_row->pedido_id = $pid;
				$legacy_row->foto_path = $path;
				$legacy_row->creado_en = NULL;
				$map[$pid][] = $legacy_row;
			}
		}

		return $map;
	}

	private function crear_tablas_si_no_existen()
	{
		$sql_pedidos = "CREATE TABLE IF NOT EXISTS pedidos (
			id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
			cliente_id INT UNSIGNED NOT NULL,
			template_id INT UNSIGNED NOT NULL,
			cantidad_material DECIMAL(10,2) NOT NULL DEFAULT 1.00,
			horas_trabajo DECIMAL(10,2) NOT NULL DEFAULT 0.00,
			margen_porcentaje DECIMAL(10,2) NOT NULL DEFAULT 0.00,
			costo_materiales DECIMAL(12,2) NOT NULL DEFAULT 0.00,
			costo_mano_obra DECIMAL(12,2) NOT NULL DEFAULT 0.00,
			costo_base DECIMAL(12,2) NOT NULL DEFAULT 0.00,
			margen_monto DECIMAL(12,2) NOT NULL DEFAULT 0.00,
			total DECIMAL(12,2) NOT NULL DEFAULT 0.00,
			estado VARCHAR(20) NOT NULL DEFAULT 'pendiente',
			foto_path VARCHAR(255) NULL,
			creado_en TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
			INDEX idx_cliente_id (cliente_id),
			INDEX idx_template_id (template_id)
		) ENGINE=InnoDB DEFAULT CHARSET=utf8";

		$sql_lineas = "CREATE TABLE IF NOT EXISTS pedido_materiales (
			id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
			pedido_id INT UNSIGNED NOT NULL,
			material_id INT UNSIGNED NOT NULL,
			cantidad DECIMAL(10,2) NOT NULL DEFAULT 1.00,
			costo_unitario DECIMAL(12,2) NOT NULL DEFAULT 0.00,
			subtotal DECIMAL(12,2) NOT NULL DEFAULT 0.00,
			INDEX idx_pedido_id (pedido_id),
			INDEX idx_material_id (material_id)
		) ENGINE=InnoDB DEFAULT CHARSET=utf8";

		$sql_fotos = "CREATE TABLE IF NOT EXISTS pedido_fotos (
			id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
			pedido_id INT UNSIGNED NOT NULL,
			foto_path VARCHAR(255) NOT NULL,
			creado_en TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
			INDEX idx_pedido_foto (pedido_id)
		) ENGINE=InnoDB DEFAULT CHARSET=utf8";

		$this->db->query($sql_pedidos);
		$this->db->query($sql_lineas);
		$this->db->query($sql_fotos);
		if (!$this->db->field_exists('foto_path', 'pedidos')) {
			$this->db->query("ALTER TABLE pedidos ADD COLUMN foto_path VARCHAR(255) NULL");
		}
		if (!$this->db->field_exists('estado', 'pedidos')) {
			$this->db->query("ALTER TABLE pedidos ADD COLUMN estado VARCHAR(20) NOT NULL DEFAULT 'pendiente'");
		}
	}

	private function asegurar_tabla_ventas_productos()
	{
		$sql = "CREATE TABLE IF NOT EXISTS inventario_ventas_productos (
			id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
			producto_id INT UNSIGNED NOT NULL DEFAULT 0,
			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);

		if (!$this->db->field_exists('pedido_id', 'inventario_ventas_productos')) {
			$this->db->query("ALTER TABLE inventario_ventas_productos ADD COLUMN pedido_id INT UNSIGNED NULL");
		}
	}
}
