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

class Orden_pedido_model extends CI_Model {

    public function listar($estado_id = null) {
        $this->db
            ->select("
                o.*,
                cli.razon_social,
                cli.nro_documento,
                m.nombre as moneda_nombre,
                m.abreviado as moneda_abreviado,
                e.codigo as estado_codigo,
                e.nombre as estado_nombre,
                CASE 
                    WHEN SUM(CASE WHEN d.orpd_saldo > 0 THEN 1 ELSE 0 END) > 0 THEN 1
                    ELSE 0
                END as tiene_saldo_factura,
                CASE 
                    WHEN e.codigo IN ('FAC', 'ANU') THEN 0
                    ELSE 1
                END as tiene_saldo_guia,
                CASE 
                    WHEN COUNT(DISTINCT god.gr_remitente_id) > 0 THEN 1
                    ELSE 0
                END AS tiene_guias
            ")
            ->from('vt_orden_pedido o')
            ->join('vt_cliente cli', 'cli.id = o.cliente_id', 'left')
            ->join('mt_moneda m', 'm.id = cli.moneda_id', 'left')
            ->join('estado e', 'e.id = o.estado_id', 'left')
            ->join('vt_orden_pedido_detalle d', 'd.orp_id = o.id', 'left')
            ->join('al_gr_remitente_orp_detalle god', 'god.orp_id = o.id', 'left');

        if ($estado_id !== null && $estado_id !== '') {
            $this->db->where('o.estado_id', $estado_id);
        }

        return $this->db
            ->group_by('o.id')
            ->order_by('o.id', 'DESC')
            ->get()
            ->result();
    }


    public function listar_estados() {
        return $this->db
            ->where('tipo', 'ORDEN PEDIDO')
            ->where('estado', 1)
            ->order_by('id', 'ASC')
            ->get('estado')
            ->result();
    }

    public function obtener($id) {
        return $this->db
            ->where('id', $id)
            ->get('vt_orden_pedido')
            ->row();
    }

    public function obtener_detalle($orp_id) {
        return $this->db
            ->select('
                d.*,
                p.codigo as producto_codigo,
                p.nombre as producto_nombre
            ')
            ->from('vt_orden_pedido_detalle d')
            ->join('vt_producto p', 'p.id = d.producto_id')
            ->where('d.orp_id', $orp_id)
            ->order_by('d.id', 'ASC')
            ->get()
            ->result();
    }

    public function obtener_historial_estados($orp_id) {
        return $this->db
            ->select('
                oe.*,
                e.nombre as estado_nombre,
                e.codigo as estado_codigo,
                u.usuario
            ')
            ->from('vt_orden_pedido_estado oe')
            ->join('estado e', 'e.id = oe.estado_id')
            ->join('usuarios u', 'u.id = oe.usuario_id', 'left')
            ->where('oe.orp_id', $orp_id)
            ->order_by('oe.id', 'ASC')
            ->get()
            ->result();
    }

    public function insertar_cabecera($data) {
        $this->db->insert('vt_orden_pedido', $data);
        return $this->db->insert_id();
    }

    public function insertar_detalle_batch($data) {
        return $this->db->insert_batch('vt_orden_pedido_detalle', $data);
    }

    public function insertar_estado($data) {
        return $this->db->insert('vt_orden_pedido_estado', $data);
    }

    public function actualizar($id, $data) {
        return $this->db
            ->where('id', $id)
            ->update('vt_orden_pedido', $data);
    }

    public function obtener_estado_por_tipo_codigo($tipo, $codigo) {
        return $this->db
            ->where('tipo', $tipo)
            ->where('codigo', $codigo)
            ->where('estado', 1)
            ->get('estado')
            ->row();
    }

    public function eliminar_detalle($orp_id) {
        return $this->db
            ->where('orp_id', $orp_id)
            ->delete('vt_orden_pedido_detalle');
    }


    public function obtener_completo($id) {
        return $this->db
            ->select('
                o.*,
                cli.razon_social,
                cli.nro_documento,
                con.nombre as contacto_nombre,
                con.celular as contacto_celular,
                loc.direccion as local_direccion,
                tc.nombre as comprobante,
                e.nombre as estado_nombre,
                e.codigo as estado_codigo,
                u.usuario as usuario_creador
            ')
            ->from('vt_orden_pedido o')
            ->join('vt_cliente cli', 'cli.id = o.cliente_id')
            ->join('vt_cliente_contacto con', 'con.id = o.contacto_id', 'left')
            ->join('vt_cliente_local loc', 'loc.id = o.local_id', 'left')
            ->join('mt_tipo_comprobante tc', 'tc.id = o.comprobante_id')
            ->join('estado e', 'e.id = o.estado_id')
            ->join('usuarios u', 'u.id = o.created_by', 'left')
            ->where('o.id', $id)
            ->get()
            ->row();
    }

    public function obtener_detalle_por_id($id) {
        return $this->db
            ->select('d.*, p.um_id_venta')
            ->from('vt_orden_pedido_detalle d')
            ->join('vt_producto p', 'p.id = d.producto_id', 'left')
            ->where('d.id', $id)
            ->get()
            ->row();
    }

    public function actualizar_detalle($id, $data) {
        return $this->db
            ->where('id', $id)
            ->update('vt_orden_pedido_detalle', $data);
    }

    public function insertar_relacion_guia_orp_detalle($data) {
        return $this->db->insert('al_gr_remitente_orp_detalle', $data);
    }

    public function detalle_op_totalmente_guiado($orp_id) {
        $detalle = $this->db
            ->select('orpd_cantidad, orpd_saldo, orpd_cantidad_guiada')
            ->from('vt_orden_pedido_detalle')
            ->where('orp_id', $orp_id)
            ->get()
            ->result();

        if (empty($detalle)) {
            return false;
        }

        foreach ($detalle as $item) {
            if ((float)$item->orpd_saldo > 0) {
                return false;
            }

            if ((float)$item->orpd_cantidad_guiada < (float)$item->orpd_cantidad) {
                return false;
            }
        }

        return true;
    }

    public function obtener_para_facturacion($id) {
        return $this->db
            ->select('
                o.*,
                cli.razon_social,
                cli.nro_documento,
                cli.domicilio_fiscal,
                cli.moneda_id,
                cli.vendedor_id,
                cli.fp_id,
                m.nombre as moneda_nombre,
                m.abreviado as moneda_abreviado,
                CONCAT(IFNULL(v.apellidos, ""), " ", IFNULL(v.nombres, "")) as vendedor_nombre
            ')
            ->from('vt_orden_pedido o')
            ->join('vt_cliente cli', 'cli.id = o.cliente_id')
            ->join('mt_moneda m', 'm.id = cli.moneda_id', 'left')
            ->join('rh_empleado v', 'v.id = cli.vendedor_id', 'left')
            ->where('o.id', $id)
            ->get()
            ->row();
    }   

    public function obtener_detalle_para_facturacion($orp_id) {
        return $this->db
            ->select('
                d.*,
                p.codigo as producto_codigo,
                p.nombre as producto_nombre,
                p.um_id_venta,
                um.abreviado as unidad_abreviada,
                p.precio_unidad,
                p.precio_doce,
                p.precio_veinticinco,
                p.precio_cincuenta,
                p.precio_cien,
                p.precio_millar,
                p.detraccion_id,
                md.nombre as detraccion_nombre,
                md.porcentaje as detraccion_porcentaje,
                md.monto_minimo as detraccion_monto_minimo,
                d.orpd_saldo as cantidad_disponible
            ')
            ->from('vt_orden_pedido_detalle d')
            ->join('vt_producto p', 'p.id = d.producto_id')
            ->join('mt_unidad_medida um', 'um.id = p.um_id_venta', 'left')
            ->join('mt_detraccion md', 'md.id = p.detraccion_id', 'left')
            ->where('d.orp_id', $orp_id)
            ->where('d.orpd_saldo >', 0)
            ->order_by('d.id', 'ASC')
            ->get()
            ->result();
    }
    public function actualizar_saldo_detalle($orpd_id, $nuevoSaldo) {
        return $this->db
            ->where('id', $orpd_id)
            ->update('vt_orden_pedido_detalle', array(
                'orpd_saldo' => $nuevoSaldo
            ));
    }

    public function obtener_detalles_con_saldo($orp_id) {
        return $this->db
            ->select('id, orpd_cantidad, orpd_saldo')
            ->from('vt_orden_pedido_detalle')
            ->where('orp_id', $orp_id)
            ->order_by('id', 'ASC')
            ->get()
            ->result();
    }

    public function actualizar_estado_orden($orp_id, $estado_id) {
        return $this->db
            ->where('id', $orp_id)
            ->update('vt_orden_pedido', array(
                'estado_id' => $estado_id
            ));
    }

    public function obtener_total_guiado_orden($orp_id) {
        $row = $this->db
            ->select('IFNULL(SUM(orpd_cantidad_guiada),0) as total_guiado, IFNULL(SUM(orpd_cantidad),0) as total_orden')
            ->from('vt_orden_pedido_detalle')
            ->where('orp_id', $orp_id)
            ->get()
            ->row();

        return $row;
    }

    public function recalcular_estado_orden($orp_id) {
        $detalles = $this->obtener_detalles_con_saldo($orp_id);

        if (empty($detalles)) {
            return false;
        }

        $todosFacturados = true;
        $hayMovimientoFacturacion = false;

        foreach ($detalles as $d) {
            if ((float)$d->orpd_saldo > 0) {
                $todosFacturados = false;
            }
            if ((float)$d->orpd_saldo < (float)$d->orpd_cantidad) {
                $hayMovimientoFacturacion = true;
            }
        }

        if ($todosFacturados) {
            return $this->actualizar_estado_orden($orp_id, 9); // FAC
        }

        $guiado = $this->obtener_total_guiado_orden($orp_id);
        $totalGuiado = $guiado ? (float)$guiado->total_guiado : 0;
        $totalOrden = $guiado ? (float)$guiado->total_orden : 0;

        if ($hayMovimientoFacturacion) {
            return $this->actualizar_estado_orden($orp_id, 6); // PAR
        }

        if ($totalOrden > 0 && $totalGuiado >= $totalOrden) {
            return $this->actualizar_estado_orden($orp_id, 8); // ENF
        }

        return $this->actualizar_estado_orden($orp_id, 5); // GEN
    }

    public function obtener_para_guia($id) {
        return $this->db
            ->select('
                o.*,
                cli.razon_social,
                cli.nro_documento,
                cli.domicilio_fiscal,
                cli.moneda_id,
                cli.vendedor_id,
                cli.fp_id,
                m.nombre as moneda_nombre,
                m.abreviado as moneda_abreviado
            ')
            ->from('vt_orden_pedido o')
            ->join('vt_cliente cli', 'cli.id = o.cliente_id')
            ->join('mt_moneda m', 'm.id = cli.moneda_id', 'left')
            ->where('o.id', $id)
            ->get()
            ->row();
    }

    public function obtener_detalle_para_guia($orp_id) {
        return $this->db
            ->select('
                d.*,
                p.codigo as producto_codigo,
                p.nombre as producto_nombre,
                p.um_id_venta,
                um.abreviado as unidad_abreviada,
                (d.orpd_cantidad - d.orpd_cantidad_guiada) as cantidad_pendiente_guia
            ')
            ->from('vt_orden_pedido_detalle d')
            ->join('vt_producto p', 'p.id = d.producto_id')
            ->join('mt_unidad_medida um', 'um.id = p.um_id_venta', 'left')
            ->where('d.orp_id', $orp_id)
            ->where('(d.orpd_cantidad - d.orpd_cantidad_guiada) >', 0)
            ->order_by('d.id', 'ASC')
            ->get()
            ->result();
    }


    public function actualizar_cantidad_guiada_detalle($id, $cantidadSumar, $usuario_id = null) {
        $detalle = $this->obtener_detalle_por_id($id);

        if (!$detalle) {
            return false;
        }

        $nuevoGuiado = (float)$detalle->orpd_cantidad_guiada + (float)$cantidadSumar;

        return $this->db
            ->where('id', $id)
            ->update('vt_orden_pedido_detalle', array(
                'orpd_cantidad_guiada' => $nuevoGuiado,
                'updated_at' => date('Y-m-d H:i:s'),
                'updated_by' => $usuario_id
            ));
    }

    public function actualizar_cantidad_guiada_detalle_desde_orden($orpd_id, $nuevaCantidadGuiada) {
        return $this->db
            ->where('id', $orpd_id)
            ->update('vt_orden_pedido_detalle', array(
                'orpd_cantidad_guiada' => $nuevaCantidadGuiada
            ));
    }

    public function obtener_detalles_para_recalculo_guia($orp_id) {
        return $this->db
            ->select('id, orpd_cantidad, orpd_cantidad_guiada')
            ->from('vt_orden_pedido_detalle')
            ->where('orp_id', $orp_id)
            ->order_by('id', 'ASC')
            ->get()
            ->result();
    }

    public function insertar_estado_orden($data) {
        return $this->db->insert('vt_orden_pedido_estado', $data);
    }

    public function recalcular_estado_orden_por_guia($orp_id) {
        $detalles = $this->obtener_detalles_para_recalculo_guia($orp_id);

        if (empty($detalles)) {
            return false;
        }

        $todosGuiados = true;
        $hayMovimientoGuia = false;

        foreach ($detalles as $d) {
            $pendiente = round((float)$d->orpd_cantidad - (float)$d->orpd_cantidad_guiada, 2);

            if ($pendiente > 0) {
                $todosGuiados = false;
            }

            if ((float)$d->orpd_cantidad_guiada > 0) {
                $hayMovimientoGuia = true;
            }
        }

        if ($todosGuiados) {
            $this->actualizar_estado_orden($orp_id, 8); // ENF
            $this->insertar_estado_orden(array(
                'orp_id' => $orp_id,
                'estado_id' => 8,
                'orp_fechaestado' => date('Y-m-d H:i:s'),
                'usuario_id' => $this->session->userdata('id')
            ));
            return true;
        }

        if ($hayMovimientoGuia) {
            $this->actualizar_estado_orden($orp_id, 6); // PAR
            $this->insertar_estado_orden(array(
                'orp_id' => $orp_id,
                'estado_id' => 6,
                'orp_fechaestado' => date('Y-m-d H:i:s'),
                'usuario_id' => $this->session->userdata('id')
            ));
            return true;
        }

        $this->actualizar_estado_orden($orp_id, 5); // GEN
        return true;
    }

}