<?php

class Utilidades
{
    public $proceso;
    public $tipo_descripcion;
    public $codigo_error = 111;

    public function __construct()
    {
        Yii::import('application.modules.contable.models.*', true);
    }

    public function getProceso()
    {
        return $this->proceso;
    }

    public function setProceso($proceso)
    {
        $this->proceso = $proceso;
    }

    public function getTipoDescripcion()
    {
        return $this->tipo_descripcion;
    }

    public function setTipoDescripcion($tipo)
    {
        $this->tipo_descripcion = $tipo;
    }

    public function checkBalance($comprobante)
    {
        $balance = Yii::app()->getDb()->createCommand('
            select sum(monto_debe) as debe,
                   sum(monto_haber) as haber, 
                   sum(monto_debe) - sum(monto_haber) as diff
            from contable.det_comprobante 
            where clv_comprobante=:comprobante
        ')->bindValues(['comprobante' => $comprobante->id])->queryRow();

        if ($balance['diff'] != 0) {
            throw new Exception("Movimientos descuadrados <strong>debe: {$balance['debe']} haber: {$balance['haber']} diferencia: {$balance['diff']}</strong>");
        }

        return true;
    }

    public function validate($debe, $haber)
    {
        if (bccomp($this->bcround(array_sum($debe)), $this->bcround(array_sum($haber)), 2) !== 0) {
            $totalDebe = Yii::app()->format->number(array_sum($debe));
            $totalHaber = Yii::app()->format->number(array_sum($haber));
            $diferencia = Yii::app()->format->number(abs(array_sum($debe) - array_sum($haber)));

            throw new Exception("Comprobante descuadrado saldos <strong>debe: {$totalDebe} haber: {$totalHaber} diferencia: {$diferencia}</strong>");
        }

        return true;
    }

    public function crearComprobante($nomina, $tipo)
    {
        $this->setProceso($nomina);
        $this->setTipoDescripcion($tipo);

        $comprobante = new Comprobante('crea');
        $comprobante->fecha_comprobante = $this->fechaComprobante();
        $comprobante->descripcion = $this->descripcion();
        $comprobante->status = 1;
        $comprobante->nro_documento = $this->referencia();

        if (! $comprobante->save()) {
            throw new Exception('Error al generar comprobante contable.', $this->codigo_error);
        }

        return $comprobante;
    }

    public function seguimientoComprobante($comprobante, $proceso, $pago, $titulo)
    {
        ProcesoComprobante::crear($comprobante, $proceso, $pago, $titulo);
    }

    public function format($number, $digitos = 2)
    {
        $multiplicador = pow(10, $digitos);
        $resultado = ((int) ($number * $multiplicador)) / $multiplicador;

        return floatval(number_format($resultado, $digitos, '.', ''));
    }

    public function fechaComprobante()
    {
        $this->validarFechaComprobante();

        return $this->getProceso()->fecha_comprobante;
    }

    /**
     * Convert a multi-dimensional array into a single-dimensional array.
     * @author Sean Cannon, LitmusBox.com | seanc@litmusbox.com
     * @param array $array the multi-dimensional array
     * @return array
     */
    public function array_flatten($array)
    {
        if (! is_array($array)) {
            return false;
        }
        $result = [];
        foreach ($array as $key => $value) {
            if (is_array($value)) {
                $result = array_merge($result, $this->array_flatten($value));
            } else {
                $result[$key] = $value;
            }
        }

        return $result;
    }

    public function debug($debe, $haber)
    {
        $totalDebe = array_sum($debe);
        $totalHaber = array_sum($haber);
        $diferencia = Math::execute(':a - :b', [
            'a' => $totalDebe,
            'b' => $totalHaber,
        ]);

        echo '<pre>';
        print_r([
            'debe' => $this->formatArrayToNumber($debe),
            'haber' => $this->formatArrayToNumber($haber),
            'total_debe' => Yii::app()->format->number(
                $this->bcround($totalDebe)
            ),
            'total_haber' => Yii::app()->format->number(
                $this->bcround($totalHaber)
            ),
            'estatus' => bccomp($diferencia, 0, 2) != 0 ? 'Descuadrado' : 'Valido',
            'diferencia' => Yii::app()->format->number($diferencia),
        ]);
        echo '</pre>';
        die();
    }

    public function bcround($strval, $precision = 2)
    {
        if (false !== ($pos = strpos($strval, '.')) && (strlen($strval) - $pos - 1) > $precision) {
            $zeros = str_repeat('0', $precision);

            return bcadd($strval, "0.{$zeros}5", $precision);
        }

        return $strval;
    }

    private function formatArrayToNumber($data)
    {
        return array_map(function ($monto) {
            return Yii::app()->format->number($monto);
        }, $data);
    }

    private function referencia()
    {
        if (in_array($this->getTipoDescripcion(), [1, 3])) {
            return $this->getProceso()->nombre_archivo;
        }

        return $this->getProceso()->getReferencia();
    }

    private function descripcion()
    {
        switch ($this->getTipoDescripcion()) {
            case 1:
                return "Aprobación {$this->getProceso()->idUnidad->descripcion}";
            case 2:
                return "Pago {$this->getProceso()->nombre_archivo} {$this->getProceso()->idUnidad->descripcion}";
            case 3:
                return "Reverso {$this->getProceso()->idUnidad->descripcion}";
        }
    }

    private function validarFechaComprobante()
    {
        if (empty($this->getProceso()->fecha_comprobante)) {
            throw new Exception('La <strong>fecha del comprobante</strong> no puede estar vacia. ', $this->codigo_error);
        }

        $respuesta = Yii::app()->db->createCommand('
            SELECT (SELECT EXISTS(
                SELECT 1
                FROM contable.ejercicios
                WHERE to_char(:fecha_comprobante::date, \'YYYY-MM\')
                    between to_char(fecha_inicio, \'YYYY-MM\')
                        and to_char(fecha_fin, \'YYYY-MM\')
                    and estatus in (1, 2)
            )) as periodo,
            (SELECT EXISTS(
                SELECT 1
                FROM contable.cierre_trimestral
                WHERE to_char(:fecha_comprobante::date, \'YYYY-MM\')
                    between to_char(fecha_desde, \'YYYY-MM\')
                        and to_char(fecha_hasta, \'YYYY-MM\')
                    AND estatus IS FALSE
            )) as trimestre,
            (SELECT EXISTS(
                SELECT *
                FROM contable.cierre_mensual
                WHERE to_char(:fecha_comprobante::date, \'YYYY-MM\')
                    between to_char(fecha_desde, \'YYYY-MM\')
                        and to_char(fecha_hasta, \'YYYY-MM\')
                    and estatus is false
            )) as mes
        ')->bindValue('fecha_comprobante', $this->getProceso()->fecha_comprobante)->queryRow();

        if (! $respuesta['periodo']) {
            throw new Exception('El <strong>periodo</strong> de la <strong>fecha comprobante</strong> seleccionado esta cerrado.', $this->codigo_error);
        }

        if (! $respuesta['trimestre']) {
            throw new Exception('El <strong>trimestre</strong> de la <strong>fecha comprobante</strong> seleccionado esta cerrado.', $this->codigo_error);
        }

        if (! $respuesta['mes']) {
            throw new Exception('El <strong>mes</strong> de la <strong>fecha comprobante</strong> seleccionado esta cerrado.', $this->codigo_error);
        }
    }

    public function configuracionAuxiliar($clave)
    {
        return Yii::app()->getDb()->createCommand('
            SELECT conf_unidad
            FROM contable.param_contables
            WHERE clave=:clave AND blnborrado IS FALSE
        ')->bindValue('clave', $clave)->queryRow()['conf_unidad'];
    }
}
