<?php

class Masivo extends Utilidades implements Agrupable
{
    protected $nomina;
    public $escenario = 1;
    protected $reverso = false;
    public $tipo_parametro = 1;
    protected $prestamos_relacionados = null;
    protected $tipo_parametro_rebaja_prestamos = 3;

    public function __construct($nomina)
    {
        $this->nomina = $nomina;
        Yii::import('application.modules.contable.models.*', true);
    }

    public function contabilizar()
    {
        if (! ParamEscenarios::conectado(1)) {
            return;
        }

        ////////////////////////////////// COMPROBANTE /////////////////////////////////
        $comprobante = $this->comprobante();

        $this->seguimientoComprobante(
            $comprobante->id,
            $this->nomina->id,
            $this->nomina->getIdComprobantePago(),
            $this->nomina->getTituloProceso()
        );
        ////////////////////////// ULTIMO COMPROBANTE /////////////////////////
        if (! $this->reverso) {
            $this->nomina->saveAttributes(['id_comprobante' => $comprobante->id]);
        } else {
            $this->nomina->saveAttributes(['id_comprobante' => null]);
        }
        ////////////////////////// MOVIMIENTOS DEL COMPROBANTE /////////////////////////
        $this->movimientos($comprobante);
    }

    protected function movimientos($comprobante)
    {
        $movimiento = new Movimiento(
            $comprobante,
            $this->nomina->fecha_referencia
        );

        $monto_aporte = $this->getMontos();

        if (! $this->configuracionAuxiliar('ret_total_retiro')) {
            $movimiento->crear(
                Parametros::getCuentaContable([
                    'clave' => 'ret_total_retiro',
                    'escenario' => null,
                    'tipo_parametro' => null,
                    'proceso' => null,
                ]),
                $monto_aporte['ret_total_retiro']
            );
        } else {
            foreach ($this->nomina->unidadesDesdeDetallePagoMasivo() as $unidad) {
                $movimiento->crear(
                    Parametros::getCuentaContable([
                        'clave' => 'ret_total_retiro',
                        'escenario' => $this->escenario,
                        'tipo_parametro' => $this->tipo_parametro,
                        'proceso' => $unidad['id_unidad'],
                    ]),
                    $monto_aporte["ret_total_retiro_{$unidad['id_unidad']}"]
                );
            }
        }

        if (! $this->configuracionAuxiliar('cta_retiro_rebaja_ingreso_diferido') && $monto_aporte['cta_retiro_rebaja_ingreso_diferido'] > 0) {
            $movimiento->crear(
                Parametros::getCuentaContable([
                    'clave' => 'cta_retiro_rebaja_ingreso_diferido',
                    'escenario' => null,
                    'tipo_parametro' => null,
                    'proceso' => null,
                ]),
                $monto_aporte['cta_retiro_rebaja_ingreso_diferido']
            );
        } else {
            foreach ((new Group([
                'by' => 'cta_retiro_rebaja_ingreso_diferido',
                'column' => 'cuenta_x_cobrar_interes',
                'escenario' => $this->escenario,
                'tipo_parametro' => $this->tipo_parametro_rebaja_prestamos,
                'data' => $this->prestamos(),
            ]))->get() as $prestamo) {
                $movimiento->crear(
                    $prestamo['cuenta_contable'],
                    $prestamo['monto']
                );
            }
        }

        if ($monto_aporte['ret_comision'] > 0) {
            if (! $this->configuracionAuxiliar('ret_comision')) {
                $movimiento->crear(
                    Parametros::getCuentaContable([
                        'clave' => 'ret_comision',
                        'escenario' => null,
                        'tipo_parametro' => null,
                        'proceso' => null,
                    ]),
                    0,
                    $monto_aporte['ret_comision']
                );
            } else {
                foreach ($this->nomina->unidadesDesdeDetallePagoMasivo() as $unidad) {
                    $movimiento->crear(
                        Parametros::getCuentaContable([
                            'clave' => 'ret_comision',
                            'escenario' => $this->escenario,
                            'tipo_parametro' => $this->tipo_parametro,
                            'proceso' => $unidad['id_unidad'],
                        ]),
                        0,
                        $monto_aporte['ret_comision']
                    );
                }
            }
        }

        if ($monto_aporte['ret_comision_bancaria'] > 0) {
            if (! $this->configuracionAuxiliar('ret_comision_bancaria')) {
                $movimiento->crear(
                    $this->nomina->bancoCuentaContable($this->nomina->id_param_banco),
                    0,
                    $monto_aporte['ret_comision_bancaria']
                );
            } else {
                foreach ($this->nomina->unidadesDesdeDetallePagoMasivo() as $unidad) {
                    $movimiento->crear(
                        Parametros::getCuentaContable([
                            'clave' => 'ret_comision_bancaria',
                            'escenario' => $this->escenario,
                            'tipo_parametro' => $this->tipo_parametro,
                            'proceso' => $unidad['id_unidad'],
                        ]),
                        0,
                        $monto_aporte['ret_comision_bancaria']
                    );
                }
            }
        }

        $movimiento->crear(
            $this->nomina->bancoCuentaContable($this->nomina->id_param_banco),
            0,
            $monto_aporte['ret_banco']
        );

        if (! $this->configuracionAuxiliar('cta_rebaja_préstamo_retiro') && $monto_aporte['cta_rebaja_préstamo_retiro'] > 0) {
            $movimiento->crear(
                Parametros::getCuentaContable([
                    'clave' => 'cta_rebaja_préstamo_retiro',
                    'escenario' => null,
                    'tipo_parametro' => null,
                    'proceso' => null,
                ]),
                0,
                $monto_aporte['cta_rebaja_préstamo_retiro']
            );
        } else {
            foreach ((new Group([
                'by' => 'cta_rebaja_préstamo_retiro',
                'column' => 'saldo_deudor_capital',
                'escenario' => $this->escenario,
                'tipo_parametro' => $this->tipo_parametro_rebaja_prestamos,
                'data' => $this->prestamos(),
            ]))->get() as $prestamo) {
                $movimiento->crear(
                    $prestamo['cuenta_contable'],
                    0,
                    $prestamo['monto']
                );
            }
        }

        if (! $this->configuracionAuxiliar('cta_rebaja_ctaxcobrar_prestamo') && $monto_aporte['cta_rebaja_ctaxcobrar_prestamo'] > 0) {
            $movimiento->crear(
                Parametros::getCuentaContable([
                    'clave' => 'cta_rebaja_ctaxcobrar_prestamo',
                    'escenario' => null,
                    'tipo_parametro' => null,
                    'proceso' => null,
                ]),
                0,
                $monto_aporte['cta_rebaja_ctaxcobrar_prestamo']
            );
        } else {
            foreach ((new Group([
                'by' => 'cta_rebaja_ctaxcobrar_prestamo',
                'column' => 'cuenta_x_cobrar_capital',
                'escenario' => $this->escenario,
                'tipo_parametro' => $this->tipo_parametro_rebaja_prestamos,
                'data' => $this->prestamos(),
            ]))->get() as $prestamo) {
                $movimiento->crear(
                    $prestamo['cuenta_contable'],
                    0,
                    $prestamo['monto']
                );
            }
        }

        if (! $this->configuracionAuxiliar('cta_rebaja_ctaxcobrar_interes') && $monto_aporte['cta_rebaja_ctaxcobrar_interes'] > 0) {
            $movimiento->crear(
                Parametros::getCuentaContable([
                    'clave' => 'cta_rebaja_ctaxcobrar_interes',
                    'escenario' => null,
                    'tipo_parametro' => null,
                    'proceso' => null,
                ]),
                0,
                $monto_aporte['cta_rebaja_ctaxcobrar_interes']
            );
        } else {
            foreach ((new Group([
                'by' => 'cta_rebaja_ctaxcobrar_interes',
                'column' => 'cuenta_x_cobrar_interes',
                'escenario' => $this->escenario,
                'tipo_parametro' => $this->tipo_parametro_rebaja_prestamos,
                'data' => $this->prestamos(),
            ]))->get() as $prestamo) {
                $movimiento->crear(
                    $prestamo['cuenta_contable'],
                    0,
                    $prestamo['monto']
                );
            }
        }

        if (! $this->configuracionAuxiliar('cta_retiro_ingreso') && $monto_aporte['cta_retiro_ingreso'] > 0) {
            $movimiento->crear(
                Parametros::getCuentaContable([
                    'clave' => 'cta_retiro_ingreso',
                    'escenario' => null,
                    'tipo_parametro' => null,
                    'proceso' => null,
                ]),
                0,
                $monto_aporte['cta_retiro_ingreso']
            );
        } else {
            foreach ((new Group([
                'by' => 'cta_retiro_ingreso',
                'column' => 'cuenta_x_cobrar_interes',
                'escenario' => $this->escenario,
                'tipo_parametro' => $this->tipo_parametro_rebaja_prestamos,
                'data' => $this->prestamos(),
            ]))->get() as $prestamo) {
                $movimiento->crear(
                    $prestamo['cuenta_contable'],
                    0,
                    $prestamo['monto']
                );
            }
        }
    }

    protected function getMontos()
    {
        $debe = (new Warp([
            'ret_total_retiro' => $this->getDebe(),
            $this->concepto('cta_retiro_rebaja_ingreso_diferido', 'cuenta_x_cobrar_interes'),
        ]))->flatten();

        $haber = $this->getHaber();

        // $this->debug($debe, $haber);

        $this->validate($debe, $haber);

        return array_merge([], $debe, $haber);
    }

    protected function comprobante()
    {
        $this->setProceso($this->nomina);

        $comprobante = new Comprobante();
        $comprobante->fecha_comprobante = $this->fechaComprobante();
        $comprobante->descripcion = "Retiro masivo {$this->nomina->descripcion}";
        $comprobante->status = 1;
        $comprobante->nro_documento = $this->nomina->num_comprobante;

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

        return $comprobante;
    }

    protected function getDebe()
    {
        if (! $this->configuracionAuxiliar('ret_total_retiro')) {
            return $this->totalMontoAprobado();
        }

        return (new Warp($this->nomina->unidadesDesdeDetallePagoMasivo()))->flatMap(function ($unidad) {
            return [
                "ret_total_retiro_{$unidad['id_unidad']}" => $this->montoAprobado($unidad['id_unidad']),
            ];
        });
    }

    protected function getHaber()
    {
        $montos = (object) Yii::app()->getDb()->createCommand('
            SELECT
                COALESCE(sum(rp.monto_gasto_administrativo), 0) AS monto_gasto_administrativo,
                COALESCE(sum(rp.monto_comision_bancaria), 0) AS monto_comision_bancaria,
                COALESCE(sum(monto_pagar), 0) AS monto_pagar
            FROM pagos.pagos_masivos_detalle pmd
            INNER JOIN retiro.retiro_parcial rp ON rp.id=pmd.id_proceso
            INNER JOIN asociado a ON rp.idasociado=a.idasociado
            INNER JOIN retiro.estatus_retiro_parcial erp ON erp.id_retiro_parcial=rp.id
                AND erp.actual IS TRUE
                AND erp.id_estatus_retiro=4
            WHERE pmd.id_pagos_masivos=:id
                AND pmd.blnborrado IS FALSE;
        ')->bindValues([
            'id' => $this->nomina->id,
        ])->queryRow();

        return (new Warp([
            'ret_comision' => $montos->monto_gasto_administrativo,
            'ret_comision_bancaria' => $montos->monto_comision_bancaria,
            'ret_banco' => $montos->monto_pagar,
            $this->concepto('cta_rebaja_préstamo_retiro', 'saldo_deudor_capital'),
            $this->concepto('cta_rebaja_ctaxcobrar_prestamo', 'cuenta_x_cobrar_capital'),
            $this->concepto('cta_rebaja_ctaxcobrar_interes', 'cuenta_x_cobrar_interes'),
            $this->concepto('cta_retiro_ingreso', 'cuenta_x_cobrar_interes'),
        ]))->flatten();
    }

    protected function totalMontoAprobado()
    {
        return Yii::app()->getDb()->createCommand('
            SELECT coalesce(sum(rp.monto_aprobado), 0) AS monto_aprobado
            FROM pagos.pagos_masivos_detalle pmd
            INNER JOIN retiro.retiro_parcial rp ON rp.id=pmd.id_proceso
            INNER JOIN asociado a ON rp.idasociado=a.idasociado
            INNER JOIN retiro.estatus_retiro_parcial erp ON erp.id_retiro_parcial=rp.id
                AND erp.actual IS TRUE
                AND erp.id_estatus_retiro=4
            WHERE pmd.id_pagos_masivos=:id
                AND pmd.blnborrado IS FALSE;
        ')->bindValues([
            'id' => $this->nomina->id,
        ])->queryRow()['monto_aprobado'];
    }

    protected function montoAprobado($unidad)
    {
        return Yii::app()->getDb()->createCommand('
                SELECT coalesce(sum(rp.monto_aprobado), 0) AS monto_aprobado
                FROM pagos.pagos_masivos_detalle pmd
                INNER JOIN retiro.retiro_parcial rp ON rp.id=pmd.id_proceso
                INNER JOIN asociado a ON rp.idasociado=a.idasociado
                INNER JOIN retiro.estatus_retiro_parcial erp ON erp.id_retiro_parcial=rp.id
                    AND erp.actual IS TRUE
                    AND erp.id_estatus_retiro=4
                WHERE pmd.id_pagos_masivos=:id
                    AND a.idunidad=:unidad
                    AND pmd.blnborrado IS FALSE;
            ')->bindValues([
            'id' => $this->nomina->id,
            'unidad' => $unidad,
        ])->queryRow()['monto_aprobado'];
    }

    protected function prestamos()
    {
        if (ConfRetiroParcial::configPagarPrestamoConRetiro()->pago_prestamo_retiro_administrador == 0) {
            return null;
        }

        $datos = Yii::app()->getDb()->createCommand('
            SELECT rp.prestamos_pago
            FROM pagos.pagos_masivos_detalle pmd
            INNER JOIN retiro.retiro_parcial rp ON rp.id=pmd.id_proceso
            WHERE pmd.id_pagos_masivos=:id
                AND pmd.blnborrado IS FALSE;
        ')->bindValues([
            'id' => $this->nomina->id,
        ])->queryAll();

        $prestamos = (new Warp($datos))->pluck('prestamos_pago');

        return (new Warp($prestamos))->flatMap(function ($prestamo) {
            return json_decode($prestamo);
        });
    }

    private function concepto($key, $field)
    {
        $datos = $this->prestamosRelacionados();

        if (! $this->configuracionAuxiliar($key)) {
            return [$key => (new Warp($datos))->sum($field)];
        }

        return (new Warp($datos))->flatMap(function ($prestamo) use ($key, $field) {
            return [
                "{$key}_{$prestamo['id_credito']}" => $prestamo[$field],
            ];
        });
    }

    protected function prestamosRelacionados()
    {
        if (is_null($this->prestamos_relacionados)) {
            $this->prestamos_relacionados = Yii::app()->getDb()->createCommand('
                    SELECT CAST(c.datos->>\'id_credito\' AS INTEGER) AS id_credito,
                           CAST(c.datos->>\'id_tipo_credito\' AS INTEGER) AS id_tipo_credito,
                           CAST(c.datos->>\'monto\' AS NUMERIC (20,2)) AS monto,
                           CAST(c.datos->>\'saldo_deudor_capital\' AS NUMERIC (20,2)) AS saldo_deudor_capital,
                           CAST(c.datos->>\'cuenta_x_cobrar_capital\' AS NUMERIC (20,2)) AS cuenta_x_cobrar_capital,
                           CAST(c.datos->>\'cuenta_x_cobrar_interes\' AS NUMERIC (20,2)) AS cuenta_x_cobrar_interes,
                           CAST(c.datos->>\'total_cuenta_x_cobrar\' AS NUMERIC (20,2)) AS total_cuenta_x_cobrar
                    FROM (
                        SELECT json_array_elements(rp.prestamos_pago) datos
                        FROM pagos.pagos_masivos_detalle pmd
                        INNER JOIN retiro.retiro_parcial rp ON rp.id=pmd.id_proceso
                        WHERE pmd.id_pagos_masivos=:id
                            AND pmd.blnborrado IS FALSE
                    ) c
                ')->bindValues([
                'id' => $this->nomina->id,
            ])->queryAll();
        }

        return $this->prestamos_relacionados;
    }

    public function groupScenario()
    {
        return $this->tipo_parametro_rebaja_prestamos;
    }

    public function groupData()
    {
        return $this->prestamos();
    }
}
