<?php

class BalanceComprobacionQuery
{
    use AttributeAccess;

    protected $attributes;

    public function __construct($attributes = [])
    {
        $this->attributes = $attributes;
    }

    public function run()
    {
        $where_cuenta = '';
        $where_total_cuenta = '';
        $where_fecha = '';
        $where_fecha = '';

        if ($this->hasAccountsRange()) {
            $where_cuenta = " AND cuenta BETWEEN '{$this->cuenta_desde}' AND '{$this->cuenta_hasta}'
                              AND titulo_mov = 2
                              OR (titulo_mov = 1
                                  AND cuenta BETWEEN '1' AND '{$this->cuenta_hasta}')";
            $where_total_cuenta = " AND cuenta BETWEEN '{$this->cuenta_desde}' AND '{$this->cuenta_hasta}' ";
        }

        if ($this->hasDateRange()) {
           $where_fecha = " AND fecha_comprobante BETWEEN (substring('{$this->fecha_desde}',7,4)||'-'||substring('{$this->fecha_desde}',4,2)||'-'||substring('{$this->fecha_desde}',1,2))::date AND (substring('{$this->fecha_hasta}',7,4)||'-'||substring('{$this->fecha_hasta}',4,2)||'-'||substring('{$this->fecha_hasta}',1,2))::date ";        }

        if ($this->hasNivel()) {
            $where_nivel = " AND nivel <= {$this->nivel} ";
        }

        if ($this->excluir_movimiento_cierre) {
            $movimiento_cierre = ' AND id_tipo_comprobante=1';
        } else {
            $movimiento_cierre = ' AND (id_tipo_comprobante=1 OR id_tipo_comprobante=3)';
        }

        $cuentas = CuentasConsolidada::model()->findAll([
            'condition' => ' blnborrado = false '.$where_cuenta.''.$where_nivel,
            'order' => 'cuenta ASC',
        ]);

        $config_contable = ['0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 5, '5' => 7, '6' => 9, '7' => 11];
        // $config_contable = [
        //     '0' => 0,
        //     '1' => 3,
        //     '2' => 5,
        //     '3' => 7,
        //     '4' => 9,
        //     '5' => 11,
        //     '6' => 13,
        //     '7' => 15,
        // ];

        $ejercicio = EjerciciosContables::model()->find('activo=1');

        $datos = [];
        $datos['attributes'] = $this->attributes;
        $datos['detalle'] = [];
        foreach ($cuentas as $cuenta) {
            $model_total_anterior = DetalleAnalitico::model()->find([
                'select' => 'coalesce(sum(monto_debe), 0) as total_debe,
                                coalesce(sum(monto_haber), 0) as total_haber,
                                coalesce(sum(monto_debe), 0) - coalesce(sum(monto_haber), 0) as total_saldo',
                'condition' => "SUBSTRING('{$cuenta->cuenta}' from 1 for '{$config_contable[$cuenta->nivel]}') = SUBSTRING(cuenta from 1 for '{$config_contable[$cuenta->nivel]}')
                                AND blnborrado = FALSE
                                AND estatus_contab=1
                                AND activo=1
                                AND clvejercicio={$ejercicio->id}
                                {$movimiento_cierre}
                                {$where_total_cuenta}
                                {$where_fecha}",
            ]);

            if ($this->fecha_desde) {
                if ($this->isBeginingOfYear()) {
                    $fechareferencia = "AND fecha_comprobante BETWEEN '{$this->fecha_desde}' AND '{$this->fecha_hasta}' AND id_tipo_comprobante=2";
                } else {
                    $fechareferencia = "AND fecha_comprobante < '{$this->fecha_desde}' ";
                }

                $model_total = DetalleAnalitico::model()->find([
                    'select' => 'coalesce(sum(monto_debe), 0) - coalesce(sum(monto_haber), 0) as total_apertura ',
                    'condition' => "SUBSTRING('{$cuenta->cuenta}' from 1 for '{$config_contable[$cuenta->nivel]}') = SUBSTRING(cuenta from 1 for '{$config_contable[$cuenta->nivel]}')
                                    AND blnborrado = FALSE
                                    AND estatus_contab=1
                                    AND activo=1
                                    AND clvejercicio={$ejercicio->id}
                                    {$where_total_cuenta}
                                    {$fechareferencia}",
                ]);
            } else {
                $model_total = DetalleAnalitico::model()->find([
                    'select' => 'coalesce(sum(monto_debe), 0) - coalesce(sum(monto_haber), 0) as total_apertura ',
                    'condition' => "SUBSTRING('{$cuenta->cuenta}' from 1 for '{$config_contable[$cuenta->nivel]}') = SUBSTRING(cuenta from 1 for '{$config_contable[$cuenta->nivel]}')
                                    AND blnborrado = FALSE
                                    AND estatus_contab=1
                                    AND activo=1
                                    AND clvejercicio={$ejercicio->id}
                                    AND id_tipo_comprobante=2
                                    {$where_total_cuenta}",
                ]);
            }

            $inicial = $model_total->total_apertura;
            $debe = $model_total_anterior->total_debe;
            $haber = $model_total_anterior->total_haber;
            $saldo = $model_total_anterior->total_saldo + $model_total->total_apertura;

            if ($this->showAccount([$inicial, $debe, $haber, $saldo])) {
                $datos['detalle'][] = [
                    'clase' => $this->isHighLevelAccount($cuenta->nivel),
                    'nivel' => $cuenta->nivel,
                    'cuenta_titulo' => $cuenta->titulo_mov == 1,
                    'cuenta' => $cuenta->cuenta,
                    'descripcion' => $cuenta->descripcion,
                    'inicial' => $inicial,
                    'debe' => $debe,
                    'haber' => $haber,
                    'saldo' => $saldo,
                ];
            }
        }

        $saldos = $this->getTitleAccounts($datos['detalle']);

        $datos['total'] = [
            'inicial' => $saldos->sum('inicial'),
            'debe' => $saldos->sum('debe'),
            'haber' => $saldos->sum('haber'),
            'saldo' => bcsub($saldos->sum('debe'), $saldos->sum('haber'), 2),
        ];

        return $datos;
    }

    private function showAccount($values)
    {
        if ($this->sin_ceros) {
            return count(array_filter($values)) > 0;
        }

        return true;
    }

    private function getTitleAccounts($accounts)
    {
        return new Warp(array_filter($accounts, function ($cuenta) {
            return $cuenta['nivel'] == 1;
        }));
    }

    public function hasAccountsRange()
    {
        return $this->cuenta_desde != null && $this->cuenta_hasta != null;
    }

    public function hasDateRange()
    {
        return $this->fecha_desde != null && $this->fecha_hasta != null;
    }

    public function hasNivel()
    {
        return $this->nivel != null;
    }

    public function isBeginingOfYear()
    {
        if (! $this->fecha_desde) {
            return false;
        }

        return date('m', strtotime($this->fecha_desde)) == 01;
    }

    public function isHighLevelAccount($nivel)
    {
        return in_array($nivel, [1, 2, 3]) ? 'cuenta_alto_nivel' : '';
    }
}
