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

class Pedidos extends CI_Controller
{
	public function __construct()
	{
		parent::__construct();

		if ($this->session->userdata('logged_in') !== TRUE) {
			redirect('login');
		}

		$this->load->model('Pedido_model');
		$this->load->model('Cliente_model');
		$this->load->model('Parametro_trabajo_model');
		$this->load->model('App_config_model');
	}

	public function index()
	{
		$templates = $this->Pedido_model->obtener_templates_pedido();
		$templates_js = array();
		foreach ($templates as $t) {
			$materiales = array();
			$base = 0.0;
			foreach ((array) $t->materiales as $m) {
				$costo = (float) $m->costo;
				$base += $costo;
				$materiales[] = array(
					'id' => (int) $m->material_id,
					'nombre' => (string) $m->nombre,
					'unidad' => (string) $m->unidad,
					'costo' => $costo
				);
			}

			$templates_js[] = array(
				'id' => (int) $t->id,
				'nombre' => (string) $t->nombre,
				'parent_nombre' => (string) $t->parent_nombre,
				'materiales_count' => (int) $t->materiales_count,
				'costo_material_base' => $base,
				'materiales' => $materiales
			);
		}

		$data['clientes'] = $this->Pedido_model->obtener_clientes();
		$data['templates'] = $templates;
		$data['templates_js'] = $templates_js;
		$data['materiales_catalogo_js'] = $this->Pedido_model->obtener_materiales_catalogo();
		$data['pedidos'] = $this->Pedido_model->obtener_pedidos();
		$data['pedidos_cerrados'] = $this->Pedido_model->obtener_pedidos_cerrados();
		$data['parametros_trabajo'] = $this->Parametro_trabajo_model->obtener();
		$data['app_config'] = $this->App_config_model->obtener();
		$this->load->view('pedidos/index', $data);
	}

	public function guardar()
	{
		$this->form_validation->set_rules('cliente_id', 'Cliente', 'trim|required|integer|greater_than[0]');
		$this->form_validation->set_rules('template_id', 'Template', 'trim|required|integer|greater_than[0]');
		$this->form_validation->set_rules('horas_trabajo', 'Cantidad de horas', 'trim|required|numeric|greater_than_equal_to[0]');
		$this->form_validation->set_rules('margen_porcentaje', 'Margen de ganancia', 'trim|required|numeric|greater_than_equal_to[0]');

		if ($this->form_validation->run() !== TRUE) {
			$this->session->set_flashdata('error', validation_errors('<div>', '</div>'));
			redirect('pedidos');
		}

		$cliente_id = (int) $this->input->post('cliente_id', TRUE);
		$template_id = (int) $this->input->post('template_id', TRUE);
		$horas_trabajo = (float) $this->input->post('horas_trabajo', TRUE);
		$margen_porcentaje = (float) $this->input->post('margen_porcentaje', TRUE);
		$material_ids = (array) $this->input->post('material_id');
		$cantidades = (array) $this->input->post('cantidad');

		if (!$this->Pedido_model->existe_cliente($cliente_id)) {
			$this->session->set_flashdata('error', 'El cliente seleccionado no existe.');
			redirect('pedidos');
		}

		$build = $this->construir_datos_pedido($template_id, $material_ids, $cantidades, $horas_trabajo, $margen_porcentaje);
		if (!$build['ok']) {
			$this->session->set_flashdata('error', $build['message']);
			redirect('pedidos');
		}

		$pedido = array(
			'cliente_id' => $cliente_id,
			'template_id' => $template_id,
			'cantidad_material' => $build['cantidad_material_total'],
			'horas_trabajo' => $horas_trabajo,
			'margen_porcentaje' => $margen_porcentaje,
			'costo_materiales' => $build['costo_materiales'],
			'costo_mano_obra' => $build['costo_mano_obra'],
			'costo_base' => $build['costo_base'],
			'margen_monto' => $build['margen_monto'],
			'total' => $build['total']
		);

		$ok = $this->Pedido_model->guardar_pedido($pedido, $build['lineas']);
		if ($ok) {
			$this->session->set_flashdata('ok', 'Pedido creado correctamente.');
		} else {
			$this->session->set_flashdata('error', 'No se pudo guardar el pedido.');
		}

		redirect('pedidos');
	}

	public function editar()
	{
		$this->form_validation->set_rules('pedido_id', 'Pedido', 'trim|required|integer|greater_than[0]');
		$this->form_validation->set_rules('cliente_id', 'Cliente', 'trim|required|integer|greater_than[0]');
		$this->form_validation->set_rules('template_id', 'Template', 'trim|required|integer|greater_than[0]');
		$this->form_validation->set_rules('horas_trabajo', 'Cantidad de horas', 'trim|required|numeric|greater_than_equal_to[0]');
		$this->form_validation->set_rules('margen_porcentaje', 'Margen de ganancia', 'trim|required|numeric|greater_than_equal_to[0]');

		if ($this->form_validation->run() !== TRUE) {
			$this->session->set_flashdata('error', validation_errors('<div>', '</div>'));
			redirect('pedidos');
		}

		$pedido_id = (int) $this->input->post('pedido_id', TRUE);
		$cliente_id = (int) $this->input->post('cliente_id', TRUE);
		$template_id = (int) $this->input->post('template_id', TRUE);
		$horas_trabajo = (float) $this->input->post('horas_trabajo', TRUE);
		$margen_porcentaje = (float) $this->input->post('margen_porcentaje', TRUE);
		$material_ids = (array) $this->input->post('material_id');
		$cantidades = (array) $this->input->post('cantidad');

		$actual = $this->Pedido_model->obtener_pedido_por_id($pedido_id);
		if (!$actual) {
			$this->session->set_flashdata('error', 'El pedido no existe.');
			redirect('pedidos');
		}
		if (!$this->Pedido_model->existe_cliente($cliente_id)) {
			$this->session->set_flashdata('error', 'El cliente seleccionado no existe.');
			redirect('pedidos');
		}

		$build = $this->construir_datos_pedido($template_id, $material_ids, $cantidades, $horas_trabajo, $margen_porcentaje);
		if (!$build['ok']) {
			$this->session->set_flashdata('error', $build['message']);
			redirect('pedidos');
		}

		$pedido = array(
			'cliente_id' => $cliente_id,
			'template_id' => $template_id,
			'cantidad_material' => $build['cantidad_material_total'],
			'horas_trabajo' => $horas_trabajo,
			'margen_porcentaje' => $margen_porcentaje,
			'costo_materiales' => $build['costo_materiales'],
			'costo_mano_obra' => $build['costo_mano_obra'],
			'costo_base' => $build['costo_base'],
			'margen_monto' => $build['margen_monto'],
			'total' => $build['total']
		);

		$ok = $this->Pedido_model->actualizar_pedido($pedido_id, $pedido, $build['lineas']);
		$this->session->set_flashdata($ok ? 'ok' : 'error', $ok ? 'Pedido actualizado correctamente.' : 'No se pudo actualizar el pedido.');
		redirect('pedidos');
	}

	public function detalle($pedido_id = 0)
	{
		$pedido_id = (int) $pedido_id;
		$this->output->set_content_type('application/json');
		if ($pedido_id <= 0) {
			$this->output->set_status_header(400)->set_output(json_encode(array('ok' => FALSE, 'message' => 'Pedido invalido.'), JSON_UNESCAPED_UNICODE));
			return;
		}

		$data = $this->Pedido_model->obtener_pedido_por_id($pedido_id);
		if (!$data) {
			$this->output->set_status_header(404)->set_output(json_encode(array('ok' => FALSE, 'message' => 'Pedido no encontrado.'), JSON_UNESCAPED_UNICODE));
			return;
		}

		$lineas = array();
		foreach ((array) $data['lineas'] as $ln) {
			$lineas[] = array(
				'material_id' => (int) $ln->material_id,
				'cantidad' => (float) $ln->cantidad
			);
		}

		$this->output->set_output(json_encode(array(
			'ok' => TRUE,
			'pedido' => array(
				'id' => (int) $data['pedido']->id,
				'cliente_id' => (int) $data['pedido']->cliente_id,
				'template_id' => (int) $data['pedido']->template_id,
				'horas_trabajo' => (float) $data['pedido']->horas_trabajo,
				'margen_porcentaje' => (float) $data['pedido']->margen_porcentaje,
				'lineas' => $lineas
			)
		), JSON_UNESCAPED_UNICODE));
	}

	public function subir_foto()
	{
		$pedido_id = (int) $this->input->post('pedido_id', TRUE);
		if ($pedido_id <= 0) {
			$this->session->set_flashdata('error', 'Pedido invalido.');
			redirect('pedidos');
		}

		$actual = $this->Pedido_model->obtener_pedido_por_id($pedido_id);
		if (!$actual) {
			$this->session->set_flashdata('error', 'El pedido no existe.');
			redirect('pedidos');
		}

		if (empty($_FILES['fotos']['name']) || !is_array($_FILES['fotos']['name'])) {
			$this->session->set_flashdata('error', 'Debes seleccionar al menos una foto.');
			redirect('pedidos');
		}

		$upload_dir = FCPATH.'uploads/pedidos/';
		if (!is_dir($upload_dir)) {
			@mkdir($upload_dir, 0755, TRUE);
		}

		$config = array(
			'upload_path' => $upload_dir,
			'allowed_types' => 'jpg|jpeg|png|webp|gif',
			'max_size' => 4096,
			'encrypt_name' => TRUE
		);

		$this->load->library('upload');
		$names = (array) $_FILES['fotos']['name'];
		$tmp = (array) $_FILES['fotos']['tmp_name'];
		$types = (array) $_FILES['fotos']['type'];
		$errors = (array) $_FILES['fotos']['error'];
		$sizes = (array) $_FILES['fotos']['size'];

		$guardadas = 0;
		$fallos = 0;
		for ($i = 0; $i < count($names); $i++) {
			if (empty($names[$i]) || (int) $errors[$i] !== 0) {
				continue;
			}

			$_FILES['foto_single'] = array(
				'name' => $names[$i],
				'type' => isset($types[$i]) ? $types[$i] : '',
				'tmp_name' => isset($tmp[$i]) ? $tmp[$i] : '',
				'error' => isset($errors[$i]) ? $errors[$i] : 0,
				'size' => isset($sizes[$i]) ? $sizes[$i] : 0
			);

			$this->upload->initialize($config, TRUE);
			if ($this->upload->do_upload('foto_single')) {
				$file = $this->upload->data();
				$path = 'uploads/pedidos/'.$file['file_name'];
				if ($this->Pedido_model->agregar_foto($pedido_id, $path)) {
					$guardadas++;
				} else {
					$fallos++;
				}
			} else {
				$fallos++;
			}
		}

		if ($guardadas > 0 && $fallos === 0) {
			$this->session->set_flashdata('ok', $guardadas === 1 ? 'Foto guardada en el pedido.' : $guardadas.' fotos guardadas en el pedido.');
		} elseif ($guardadas > 0) {
			$this->session->set_flashdata('ok', $guardadas.' fotos guardadas. Algunas no se pudieron subir.');
		} else {
			$this->session->set_flashdata('error', 'No se pudo guardar ninguna foto.');
		}
		redirect('pedidos');
	}

	public function finalizar()
	{
		$pedido_id = (int) $this->input->post('pedido_id', TRUE);
		$accion = trim((string) $this->input->post('accion', TRUE));

		if ($pedido_id <= 0) {
			$this->session->set_flashdata('error', 'Pedido invalido.');
			redirect('pedidos');
		}

		$actual = $this->Pedido_model->obtener_pedido_por_id($pedido_id);
		if (!$actual) {
			$this->session->set_flashdata('error', 'El pedido no existe.');
			redirect('pedidos');
		}
		$estado_actual = isset($actual['pedido']->estado) ? (string) $actual['pedido']->estado : 'pendiente';

		if ($accion === 'add_producto') {
			if ($estado_actual === 'producto') {
				$this->session->set_flashdata('ok', 'Este pedido ya esta en estado Producto.');
				redirect('inventario/productos');
			}

			$ok = $this->Pedido_model->agregar_pedido_a_productos($pedido_id);
			if ($ok) {
				$this->Pedido_model->actualizar_estado($pedido_id, 'producto');
				$this->session->set_flashdata('ok', 'Pedido agregado a productos.');
				redirect('inventario/productos');
			} else {
				$this->session->set_flashdata('error', 'No se pudo agregar a productos.');
			}
			redirect('pedidos');
		}

		if ($accion === 'finalizar_venta') {
			$ok_estado = $this->Pedido_model->actualizar_estado($pedido_id, 'finalizado');
			$ok_venta = $this->Pedido_model->registrar_venta_finalizada($pedido_id);
			$ok = $ok_estado && $ok_venta;
			$this->session->set_flashdata($ok ? 'ok' : 'error', $ok ? 'Venta finalizada correctamente.' : 'No se pudo finalizar la venta.');
			redirect('pedidos');
		}

		$this->session->set_flashdata('error', 'Accion invalida.');
		redirect('pedidos');
	}

	public function crear_cliente_ajax()
	{
		$this->output->set_content_type('application/json');

		$nombre = trim((string) $this->input->post('nombre', TRUE));
		$telefono = trim((string) $this->input->post('telefono', TRUE));

		if ($nombre === '') {
			$this->output->set_status_header(400);
			$this->output->set_output(json_encode(array(
				'ok' => FALSE,
				'message' => 'El nombre del cliente es obligatorio.'
			), JSON_UNESCAPED_UNICODE));
			return;
		}

		if (strlen($nombre) > 120) {
			$this->output->set_status_header(400);
			$this->output->set_output(json_encode(array(
				'ok' => FALSE,
				'message' => 'El nombre es demasiado largo.'
			), JSON_UNESCAPED_UNICODE));
			return;
		}

		if ($telefono !== '' && strlen($telefono) > 40) {
			$this->output->set_status_header(400);
			$this->output->set_output(json_encode(array(
				'ok' => FALSE,
				'message' => 'El telefono es demasiado largo.'
			), JSON_UNESCAPED_UNICODE));
			return;
		}

		$ok = $this->Cliente_model->crear(array(
			'nombre' => $nombre,
			'cedula' => '',
			'telefono' => $telefono,
			'correo' => '',
			'instagram' => '',
			'direccion' => '',
			'nota' => ''
		));

		if (!$ok) {
			$this->output->set_status_header(500);
			$this->output->set_output(json_encode(array(
				'ok' => FALSE,
				'message' => 'No se pudo crear el cliente.'
			), JSON_UNESCAPED_UNICODE));
			return;
		}

		$id = (int) $this->db->insert_id();
		$label = $nombre.($telefono !== '' ? ' - '.$telefono : '');
		$this->output->set_output(json_encode(array(
			'ok' => TRUE,
			'cliente' => array(
				'id' => $id,
				'label' => $label
			)
		), JSON_UNESCAPED_UNICODE));
	}

	private function construir_datos_pedido($template_id, $material_ids, $cantidades, $horas_trabajo, $margen_porcentaje)
	{
		$template = $this->Pedido_model->obtener_template_por_id($template_id);
		if (!$template) {
			return array('ok' => FALSE, 'message' => 'El template seleccionado no existe.');
		}
		if (empty($material_ids)) {
			return array('ok' => FALSE, 'message' => 'Debes indicar cantidades por material.');
		}

		$costos_materiales_map = $this->Pedido_model->obtener_costos_por_material_ids($material_ids);
		if (empty($costos_materiales_map)) {
			return array('ok' => FALSE, 'message' => 'No se pudieron validar los materiales del pedido.');
		}

		$params = $this->Parametro_trabajo_model->obtener();
		$mano_obra_hora = isset($params['monto_mano_obra']) ? (float) $params['monto_mano_obra'] : 0.0;

		$costo_materiales = 0.0;
		$cantidad_material_total = 0.0;
		$lineas_map = array();

		foreach ((array) $material_ids as $i => $mid_raw) {
			$mid = (int) $mid_raw;
			$cant = isset($cantidades[$i]) ? (float) $cantidades[$i] : -1;
			if ($mid <= 0 || !isset($costos_materiales_map[$mid])) {
				return array('ok' => FALSE, 'message' => 'Hay materiales invalidos en el pedido.');
			}
			if ($cant < 0) {
				return array('ok' => FALSE, 'message' => 'Las cantidades por material no son validas.');
			}
			if ($cant == 0) {
				continue;
			}

			if (!isset($lineas_map[$mid])) {
				$lineas_map[$mid] = array(
					'material_id' => $mid,
					'cantidad' => 0.0,
					'costo_unitario' => (float) $costos_materiales_map[$mid],
					'subtotal' => 0.0
				);
			}
			$lineas_map[$mid]['cantidad'] += $cant;
		}

		if (empty($lineas_map)) {
			return array('ok' => FALSE, 'message' => 'Debes colocar al menos un material con cantidad mayor a cero.');
		}

		$lineas = array();
		foreach ($lineas_map as $ln) {
			$ln['subtotal'] = $ln['cantidad'] * $ln['costo_unitario'];
			$costo_materiales += $ln['subtotal'];
			$cantidad_material_total += $ln['cantidad'];
			$lineas[] = $ln;
		}

		$costo_mano_obra = $horas_trabajo * $mano_obra_hora;
		$costo_base = $costo_materiales + $costo_mano_obra;
		$margen_monto = $costo_base * ($margen_porcentaje / 100);
		$total = $costo_base + $margen_monto;

		return array(
			'ok' => TRUE,
			'lineas' => $lineas,
			'cantidad_material_total' => $cantidad_material_total,
			'costo_materiales' => $costo_materiales,
			'costo_mano_obra' => $costo_mano_obra,
			'costo_base' => $costo_base,
			'margen_monto' => $margen_monto,
			'total' => $total
		);
	}
}
