<?php

class Individual extends Utilidades implements Agrupable
{
    protected $pago;
    protected $prestamo;
    public $escenario = 4;
    protected $tipo_prestamo = 3;
    protected $tipo_afianzadora = 2;
    public $tipo_parametro_rebaja_prestamos = 3;
    protected $escenario_cuenta_x_cobrar_retenciones = 9;

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

    public function contabilizar()
    {
        if (! ParamEscenarios::conectado($this->escenario)) {
            return;
        }

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

        $this->seguimientoComprobante(
            $comprobante->id,
            $this->prestamo->id,
            $this->pago->id,
            $this->pago->id_nombre_proceso
        );
        ////////////////////////// MOVIMIENTOS DEL COMPROBANTE /////////////////////////
        $this->movimientos($comprobante);
    }

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

        $monto_aporte = $this->getMontos();

        $movimiento->crear(
            Parametros::getCuentaContable([
                'clave' => 'cta_plazo_prestamo',
                'proceso' => 'id_tipo_credito',
                'escenario' => $this->escenario,
                'tipo_parametro' => $this->tipo_prestamo,
                'proceso' => $this->prestamo->id_tipo_credito,
            ]),
            $monto_aporte['cta_plazo_prestamo']
        );

        $prestamosSeleccionados = $this->prestamosSeleccionados();

        foreach ((new Group([
            'by' => 'cta_ingresos_interes',
            'tipo_parametro' => $this->tipo_prestamo,
            'data' => $prestamosSeleccionados,
            'column' => 'interes_cuotas_no_afectadas',
            'escenario' => $this->escenario_cuenta_x_cobrar_retenciones,
        ]))->get() as $prestamo) {
            $movimiento->crear(
                $prestamo['cuenta_contable'],
                $prestamo['monto']
            );
        }

        foreach ((new Group([
            'by' => 'cta_x_cobrar_capital',
            'tipo_parametro' => $this->tipo_prestamo,
            'data' => $prestamosSeleccionados,
            'column' => 'capital_cuotas_no_afectadas',
            'escenario' => $this->escenario_cuenta_x_cobrar_retenciones,
        ]))->get() as $prestamo) {
            $movimiento->crear(
                $prestamo['cuenta_contable'],
                0,
                $prestamo['monto']
            );
        }

        foreach ((new Group([
            'by' => 'cta_ingresos_interes',
            'tipo_parametro' => $this->tipo_prestamo,
            'data' => $prestamosSeleccionados,
            'column' => 'interes_cuotas_no_afectadas',
            'escenario' => $this->escenario_cuenta_x_cobrar_retenciones,
        ]))->get() as $prestamo) {
            $movimiento->crear(
                $prestamo['cuenta_contable'],
                0,
                $prestamo['monto']
            );
        }

        foreach ((new Group([
            'by' => 'cta_retenciones_ingreso_interes',
            'tipo_parametro' => $this->tipo_prestamo,
            'data' => $prestamosSeleccionados,
            'column' => 'interes_cuotas_no_afectadas',
            'escenario' => $this->escenario,
        ]))->get() as $prestamo) {
            $movimiento->crear(
                $prestamo['cuenta_contable'],
                0,
                $prestamo['monto']
            );
        }

        if (! empty($this->prestamo->gastos_administrativo)) {
            $movimiento->crear(
                Parametros::getCuentaContable([
                    'clave' => 'cta_comision_administrativa',
                    'escenario' => $this->escenario,
                    'tipo_parametro' => $this->tipo_prestamo,
                    'proceso' => $this->prestamo->id_tipo_credito,
                ]),
                0,
                $monto_aporte['cta_comision_administrativa']
            );
        }

        if (! empty($this->prestamo->gastos_administrativos_afianzadora)) {
            $movimiento->crear(
                $this->cuentaAuxiliarAfianzadora(),
                0,
                $monto_aporte['cta_fianza_prestamo']
            );
        }

        if (array_key_exists('cta_rebaja_prestamo', $monto_aporte)) {
            $movimiento->crear(
                $this->prestamo->bancoCuentaContable($this->pago->id_banco),
                0,
                $monto_aporte['cta_rebaja_prestamo']
            );
        }

        $datosAgrupados = OrderByCuentaContable::comprobante($this)
            ->clave('cta_plazo_prestamo')
            ->groupBy('cta_rebaja_prestamo_anterior');

        if (count($datosAgrupados) > 0 && ! empty($this->prestamo->prestamos_seleccionados)) {
            foreach ($datosAgrupados as $prestamo) {
                $movimiento->crear(
                    $prestamo['cuenta_contable'],
                    0,
                    $prestamo['monto']
                );
            }
        }
    }

    protected function getMontos()
    {
        $debe = (new Warp([
            'cta_plazo_prestamo' => $this->monto(),
            'cta_retenciones_ingreso_diferido' => $this->convert('cta_retenciones_ingreso_diferido', 'interes_cuotas_no_afectadas'),
        ]))->flatten();

        $haber = (new Warp([
            'cta_comision_administrativa' => $this->prestamo->gastos_administrativo,
            'cta_fianza_prestamo' => $this->comisionAfianzadora(),
            'cta_rebaja_prestamo' => $this->montoAnterior(),
            'cta_rebaja_prestamo_anterior' => $this->convert('cta_rebaja_prestamo_anterior', 'monto'),
            'cta_retenciones_cta_x_cobrar_capital' => $this->convert('cta_retenciones_cta_x_cobrar_capital', 'capital_cuotas_no_afectadas'),
            'cta_retenciones_cta_x_cobrar_interes' => $this->convert('cta_retenciones_cta_x_cobrar_interes', 'interes_cuotas_no_afectadas'),
            'cta_retenciones_ingreso_interes' => $this->convert('cta_retenciones_ingreso_interes', 'interes_cuotas_no_afectadas'),
        ]))->flatten();

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

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

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

    protected function comisionAfianzadora()
    {
        return $this->prestamo->gastos_administrativos_afianzadora
            + $this->prestamo->gastos_administrativos_afianzadora_caja;
    }

    protected function montoAnterior()
    {
        return $this->prestamo->monto_credito_depositar;
    }

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

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

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

        return $comprobante;
    }

    protected function descripcion()
    {
        $asociado = $this->prestamo->idAsociado;

        return  'Préstamo '.ucwords($asociado->nombre).' '.ucwords($asociado->apellidos).' Céd: '.$asociado->cedula;
    }

    protected function reestructurado()
    {
        return $this->prestamo->refinanciado == 2;
    }

    protected function refinanciado()
    {
        return $this->prestamo->refinanciado == 1;
    }

    protected function convert($key, $field)
    {
        $prestamos = $this->prestamosSeleccionados();

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

    protected function prestamosSeleccionados()
    {
        if ($this->prestamo->prestamos_seleccionados === null) {
            return [];
        }
        
        return json_decode($this->prestamo->prestamos_seleccionados);
    }

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

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

    /**
     * Obtiene el tipo de credito, basado en el id_credito_padre del préstamo refinanciado.
     *
     * @return int id_tipo_credito préstamo anterior
     */
    protected function tipoCreditoPadre()
    {
        return Yii::app()->getDb()->createCommand('
            SELECT id_tipo_credito
            FROM prestamos.credito
            WHERE id=(SELECT id_credito_padre
                     FROM prestamos.credito
                     WHERE id=:id)
        ')->bindValue('id', $this->prestamo->id)->queryRow()['id_tipo_credito'];
    }

    /**
     * suma los montos del los gastos administrativos y afianzadora si el gasto es financiado.
     *
     * @return float
     */
    protected function monto()
    {
        $monto = $this->prestamo->monto_credito;

        if ($this->gastoAdministrativoFinanciado()) {
            $monto += $this->prestamo->gastos_administrativo;
        }

        if ($this->gastoAdministrativoAfianzadoraFinanciado()) {
            $monto += $this->prestamo->gastos_administrativos_afianzadora;
        }

        return $monto;
    }

    /**
     * Consulta si el gasto administrativo está financiado.
     *
     * @return bool
     */
    protected function gastoAdministrativoFinanciado()
    {
        return ! Yii::app()->getDb()->createCommand('
            SELECT descontar
            FROM prestamos.tipo_credito_gastos_administrativo
            WHERE id_tipo_credito=:id AND blnborrado IS FALSE;
        ')->bindValue('id', $this->prestamo->id_tipo_credito)->queryScalar();
    }

    /**
     * Consulta si el gasto administrativo afianzadora está finaciado.
     *
     * @return bool
     */
    protected function gastoAdministrativoAfianzadoraFinanciado()
    {
        return ! Yii::app()->getDb()->createCommand('
            SELECT descontar_grantia_afianzadora
            FROM prestamos.tipo_credito
            WHERE id=:id;
        ')->bindValue('id', $this->prestamo->id_tipo_credito)->queryScalar();
    }

    protected function cuentaAuxiliarAfianzadora()
    {
        if (! $this->configuracionAuxiliar('cta_fianza_prestamo')) {
            return Parametros::getCuentaContable([
                'clave' => 'cta_fianza_prestamo',
                'escenario' => null,
                'tipo_parametro' => null,
                'proceso' => null,
            ]);
        }

        return AnfianzadoraProveedorCuentaContable::get($this->prestamo->id_afianzadora);
    }
}
