<?php
namespace Incoviba\Repository\Venta;

use Incoviba\Common\Define;
use Incoviba\Common\Ideal;
use Incoviba\Common\Implement;
use Incoviba\Model;
use Incoviba\Repository;
use Incoviba\Service;

class Cuota extends Ideal\Repository
{
    public function __construct(
        Define\Connection                       $connection,
        protected Pie                           $pieRepository,
        protected Repository\Contabilidad\Banco $bancoRepository,
        protected Service\Venta\Pago            $pagoService
    )
    {
        parent::__construct($connection);
        $this->setTable('cuota');
    }

    public function create(?array $data = null): Model\Venta\Cuota
    {
        $map = (new Implement\Repository\MapperParser(['uf', 'numero']))
            ->register('pie', (new Implement\Repository\Mapper())
                ->setFunction(function($data) {
                    return $this->pieRepository->fetchById($data['pie']);
                }))
            ->register('fecha', new Implement\Repository\Mapper\DateTime('fecha'))
            ->register('valor_$', (new Implement\Repository\Mapper())
                ->setProperty('valor')
            )
            ->register('estado', new Implement\Repository\Mapper\Boolean('estado'))
            ->register('banco', (new Implement\Repository\Mapper())
                ->setFunction(function($data) {
                    if ($data['banco'] === null or $data['banco'] === 0 or trim($data['banco']) === '') {
                        return null;
                    }
                    return $this->bancoRepository->fetchById($data['banco']);
                }))
            ->register('fecha_pago', (new Implement\Repository\Mapper\DateTime('fecha_pago', 'fechaPago'))
                ->setDefault(null))
            ->register('abonado', (new Implement\Repository\Mapper\Boolean('abonado'))
                ->setDefault(null))
            ->register('fecha_abonado', (new Implement\Repository\Mapper\DateTime('fecha_abonado', 'fechaAbonado'))
                ->setDefault(null))
            ->register('pago', (new Implement\Repository\Mapper())
                ->setFunction(function($data) {
                    if ($data['pago'] === null) {
                        return null;
                    }
                    return $this->pagoService->getById($data['pago']);
                }));
        return $this->parseData(new Model\Venta\Cuota(), $data, $map);
    }

    public function save(Define\Model $model): Model\Venta\Cuota
    {
        $model->id = $this->saveNew(
            ['pie', 'fecha', 'valor_$', 'estado', 'banco', 'fecha_pago', 'abonado', 'fecha_abono', 'uf', 'pago', 'numero'],
            [$model->pie->id, $model->fecha->format('Y-m-d H:i:s'), $model->valor, $model->estado ? 1 : 0, $model->banco?->id,
                null, null, null,
                $model->uf, $model->pago->id, $model->numero]
        );
        return $model;
    }

    public function edit(Define\Model $model, array $new_data): Model\Venta\Cuota
    {
        return $this->update($model, ['pie', 'fecha', 'valor', 'estado', 'banco', 'fecha_pago', 'abonado', 'fecha_abonado', 'uf', 'pago', 'numero'], $new_data);
    }

    public function fetchHoy(): array
    {
        $query = $this->connection->getQueryBuilder()
            ->select('a.*')
            ->from("{$this->getTable()} a")
            ->joined('JOIN pago ON pago.id = a.pago')
            ->joined('JOIN (SELECT e1.* FROM estado_pago e1 JOIN (SELECT MAX(id) AS id, pago FROM estado_pago GROUP BY pago) e0 ON e0.id = e1.id) ep ON ep.pago = pago.id')
            ->joined('JOIN tipo_estado_pago tep ON tep.id = ep.estado')
            ->joined('JOIN venta ON venta.pie = a.pie')
            ->joined('JOIN (SELECT ev1.* FROM estado_venta ev1 JOIN (SELECT MAX(id) AS id, venta FROM estado_venta GROUP BY venta) ev0 ON ev0.id = ev1.id) ev ON ev.venta = venta.id')
            ->joined('JOIN tipo_estado_venta tev ON tev.id = ev.estado')
            ->where('tep.descripcion = ? AND pago.fecha = CURDATE() AND tev.descripcion IN (?, ?, ?)');
        return $this->fetchMany($query, ['no pagado', 'vigente', 'escriturando', 'firmado por inmobiliaria']);
    }
    public function fetchPendientes(): array
    {
        $query = $this->connection->getQueryBuilder()
            ->select(['a.`id` AS cuota_id', 'venta.id AS venta_id', 'proyecto.descripcion AS Proyecto', 'unidad.descripcion AS Departamento',
                'pago.valor AS Valor', 'pago.fecha', 'CONCAT_WS(" - ", a.numero, pie.cuotas) AS Numero', 'banco.nombre AS Banco',
                'CONCAT_WS(" ", propietario.nombres, propietario.apellido_paterno, propietario.apellido_materno) AS Propietario'])
            ->from("{$this->getTable()} a")
            ->joined('JOIN pago ON pago.id = a.pago')
            ->joined('JOIN (SELECT e1.* FROM estado_pago e1 JOIN (SELECT MAX(id) AS id, pago FROM estado_pago GROUP BY pago) e0 ON e0.id = e1.id) ep ON ep.pago = pago.id')
            ->joined('JOIN tipo_estado_pago tep ON tep.id = ep.estado')
            ->joined('JOIN pie ON pie.id = a.pie')
            ->joined('JOIN venta ON venta.pie = a.pie')
            ->joined('JOIN (SELECT ev1.* FROM estado_venta ev1 JOIN (SELECT MAX(id) AS id, venta FROM estado_venta GROUP BY venta) ev0 ON ev0.id = ev1.id) ev ON ev.venta = venta.id')
            ->joined('JOIN tipo_estado_venta tev ON tev.id = ev.estado')
            ->joined('JOIN propietario ON propietario.rut = venta.propietario')
            ->joined('JOIN propiedad_unidad pu ON pu.propiedad = venta.propiedad')
            ->joined('JOIN unidad ON unidad.id = pu.unidad AND pu.principal = 1')
            ->joined('JOIN proyecto_tipo_unidad ptu ON ptu.id = unidad.pt')
            ->joined('JOIN proyecto ON proyecto.id = ptu.proyecto')
            ->joined('JOIN banco ON banco.id = pago.banco')
            ->where('tep.descripcion = ? AND pago.fecha < CURDATE() AND tev.descripcion IN (?, ?, ?)')
            ->order('pago.fecha DESC');
        return $this->fetchAsArray($query, ['no pagado', 'vigente', 'escriturando', 'firmado por inmobiliaria']);
    }
    public function fetchDepositadas(): array
    {
        $query = $this->connection->getQueryBuilder()
            ->select(['a.`id` AS cuota_id', 'venta.id AS venta_id', 'proyecto.descripcion AS Proyecto', 'unidad.descripcion AS Departamento',
                'pago.valor AS Valor', 'pago.fecha', 'CONCAT_WS(" - ", a.numero, pie.cuotas) AS Numero', 'banco.nombre AS Banco', 'ep.fecha AS Fecha Depositada',
                'CONCAT_WS(" ", propietario.nombres, propietario.apellido_paterno, propietario.apellido_materno) AS Propietario'])
            ->from("{$this->getTable()} a")
            ->joined('JOIN pago ON pago.id = a.pago')
            ->joined('JOIN (SELECT e1.* FROM estado_pago e1 JOIN (SELECT MAX(id) AS id, pago FROM estado_pago GROUP BY pago) e0 ON e0.id = e1.id) ep ON ep.pago = pago.id')
            ->joined('JOIN tipo_estado_pago tep ON tep.id = ep.estado')
            ->joined('JOIN pie ON pie.id = a.pie')
            ->joined('JOIN venta ON venta.pie = a.pie')
            ->joined('JOIN (SELECT ev1.* FROM estado_venta ev1 JOIN (SELECT MAX(id) AS id, venta FROM estado_venta GROUP BY venta) ev0 ON ev0.id = ev1.id) ev ON ev.venta = venta.id')
            ->joined('JOIN tipo_estado_venta tev ON tev.id = ev.estado')
            ->joined('JOIN propietario ON propietario.rut = venta.propietario')
            ->joined('JOIN propiedad_unidad pu ON pu.propiedad = venta.propiedad')
            ->joined('JOIN unidad ON unidad.id = pu.unidad AND pu.principal = 1')
            ->joined('JOIN proyecto_tipo_unidad ptu ON ptu.id = unidad.pt')
            ->joined('JOIN proyecto ON proyecto.id = ptu.proyecto')
            ->joined('JOIN banco ON banco.id = pago.banco')
            ->where('tep.descripcion = ?')
            ->where('pago.fecha < CURDATE()')
            ->where('tev.descripcion IN (?, ?, ?)')
            ->order('pago.fecha DESC');
        return $this->fetchAsArray($query, ['depositado', 'vigente', 'escriturando', 'firmado por inmobiliaria']);
    }
    public function fetchDatosPorVencer(): array
    {
        $query = $this->connection->getQueryBuilder()
            ->select(['p1.`fecha` AS Fecha', 'v1.`descripcion` AS Proyecto', 'COUNT(a.`id`) AS Cantidad'])
            ->from("{$this->getTable()} a")
            ->joined('JOIN (
            SELECT `pago`.`id`, `pago`.`fecha` FROM `pago` 
                JOIN (SELECT e1.* FROM `estado_pago` e1 
                    JOIN (SELECT MAX(`id`) AS `id`, `pago` FROM `estado_pago` GROUP BY `pago`) e0 ON e0.`id` = e1.`id`) ep ON ep.`pago` = `pago`.`id`
                JOIN `tipo_estado_pago` tep ON tep.`id` = ep.`estado` AND tep.`descripcion` = :tep) p1 ON p1.id = a.`pago`')
            ->joined('JOIN (
            SELECT `venta`.`pie`, `venta`.`propiedad`, `proyecto`.`descripcion` FROM `venta` 
                JOIN (SELECT ev1.* FROM `estado_venta` ev1
                    JOIN (SELECT MAX(`id`) AS `id`, `venta` FROM `estado_venta` GROUP BY `venta`) ev0 ON ev0.`id` = ev1.`id`) ev ON ev.`venta` = `venta`.`id`
                JOIN `tipo_estado_venta` tev ON tev.`id` = ev.`estado` AND tev.`descripcion` IN (:tev1, :tev2, :tev3)
                JOIN `propiedad_unidad` pu ON pu.`propiedad` = `venta`.`propiedad`
                JOIN `unidad` ON `unidad`.`id` = pu.`unidad` JOIN `proyecto_tipo_unidad` ptu ON ptu.`id` = `unidad`.`pt` 
                JOIN `proyecto` ON `proyecto`.`id` = ptu.`proyecto`) v1 ON v1.`pie` = a.`pie`')
            ->where('p1.`fecha` BETWEEN DATE_ADD(CURDATE(), INTERVAL 1 DAY) AND DATE_ADD(CURDATE(), INTERVAL 1 MONTH)')
            ->group('p1.`fecha`, v1.`descripcion`')
            ->order('p1.`fecha`, v1.`descripcion`');
        return $this->fetchAsArray($query, ['tep' => 'no pagado', 'tev1' => 'vigente', 'tev2' => 'escriturando', 'tev3' => 'firmado por inmobiliaria']);

        /*$query = "SELECT p1.`fecha` AS 'Fecha', v1.`descripcion` AS 'Proyecto', COUNT(a.`id`) AS 'Cantidad'
FROM `{$this->getTable()}` a
    JOIN (
        SELECT `pago`.`id`, `pago`.`fecha`
        FROM `pago`
            JOIN (
                SELECT e1.*
                FROM `estado_pago` e1
                    JOIN (
                        SELECT MAX(`id`) AS 'id', `pago`
                        FROM `estado_pago`
                        GROUP BY `pago`
                    ) e0 ON e0.`id` = e1.`id`
            ) ep ON ep.`pago` = `pago`.`id`
            JOIN `tipo_estado_pago` tep ON tep.`id` = ep.`estado` AND tep.`descripcion` = :no_pagado
    ) p1 ON p1.id = a.`pago`
    JOIN (
        SELECT `venta`.`pie`, `venta`.`propiedad`, `proyecto`.`descripcion`
        FROM `venta`
            JOIN (
                SELECT ev1.*
                FROM `estado_venta` ev1
                    JOIN (
                        SELECT MAX(`id`) AS 'id', `venta`
                        FROM `estado_venta`
                        GROUP BY `venta`
                    ) ev0 ON ev0.`id` = ev1.`id`
            ) ev ON ev.`venta` = `venta`.`id`
            JOIN `tipo_estado_venta` tev ON tev.`id` = ev.`estado` AND tev.`descripcion` IN (:estados)
            JOIN `propiedad_unidad` pu ON pu.`propiedad` = `venta`.`propiedad` AND pu.`principal` = 1
            JOIN `unidad` ON `unidad`.`id` = pu.`unidad`
            JOIN `proyecto_tipo_unidad` ptu ON ptu.`id` = `unidad`.`pt`
            JOIN `proyecto` ON `proyecto`.`id` = ptu.`proyecto`
    ) v1 ON v1.`pie` = a.`pie`
WHERE p1.`fecha` BETWEEN DATE_ADD(CURDATE(), INTERVAL 1 DAY) AND DATE_ADD(CURDATE(), INTERVAL 1 MONTH)
GROUP BY p1.`fecha`, v1.`descripcion`
ORDER BY p1.`fecha`, v1.`descripcion`";
        return $this->fetchAsArray($query);*/
    }

    /**
     * @param int $pie_id
     * @return array
     * @throws Implement\Exception\EmptyResult
     */
    public function fetchByPie(int $pie_id): array
    {
        $query = $this->connection->getQueryBuilder()
            ->select()
            ->from($this->getTable())
            ->where('pie = :pie_id')
            ->group('id');
        return $this->fetchMany($query, compact('pie_id'));
    }
    public function fetchVigenteByPie(int $pie_id): array
    {
        $query = $this->connection->getQueryBuilder()
            ->select('a.*')
            ->from("{$this->getTable()} a")
            ->joined('JOIN pago ON pago.id = a.pago')
            ->joined('JOIN (SELECT e1.* FROM estado_pago e1 JOIN (SELECT MAX(id) AS id, pago FROM estado_pago GROUP BY pago) e0 ON e0.id = e1.id) ep ON ep.pago = pago.id')
            ->joined('JOIN tipo_estado_pago tep ON tep.id = ep.estado')
            ->where('a.pie = :pie_id')
            ->where('tep.active = 1')
            ->group('a.id');
        return $this->fetchMany($query, compact('pie_id'));
        /*$query = "SELECT a.*
FROM `{$this->getTable()}` a
    JOIN `pago` ON `pago`.`id` = a.`pago`
    JOIN (SELECT e1.* FROM `estado_pago` e1 JOIN (SELECT MAX(`id`) AS 'id', `pago` FROM `estado_pago` GROUP BY `pago`) e0 ON e0.`id` = e1.`id`) ep ON ep.`pago` = `pago`.`id`
    JOIN `tipo_estado_pago` tep ON tep.`id` = ep.`estado`
WHERE a.`pie` = ? AND tep.`active` = 1
GROUP BY a.`id`";
        return $this->fetchMany($query, [$pie_id]);*/
    }
    public function fetchByPago(int $pago_id): Model\Venta\Cuota
    {
        $query = $this->connection->getQueryBuilder()
            ->select()
            ->from($this->getTable())
            ->where('pago = ?');
        return $this->fetchOne($query, [$pago_id]);
    }
    public function filterData(array $data): array
    {
        return array_intersect_key($data, array_fill_keys(['pie', 'fecha', 'valor', 'estado', 'banco', 'fecha_pago', 'abonado', 'fecha_abonado', 'uf', 'pago', 'numero'], 0));
    }
}
