<?php
namespace App\Service\Informe\Contabilidad;

use DateTimeInterface;
use DateTimeImmutable;
use DateInterval;

use App\Service\Informe\Informe;
use Incoviba\old\Proyecto\Proyecto;
use Incoviba\old\Venta\Venta;
use Incoviba\old\Venta\Pago;

/**
 * Resumen para revisar el libro mayor de un proyecto para cierto mes (sumando el año anterior)
 * Obtiene lo pagado para cada departamento
 *  - anticipo (cuotas)
 *  - reajuste
 *  - abonos
 *  - credito
 *  - subsidio
 *  - bono
 *  - promociones
 */
class Resumen
{
    protected string $separator;
    public function __construct(string $separator = ';')
    {
        $this->separator = $separator;
    }

    protected function getVentas($id_proyecto)
    {
        $proyecto = model(Proyecto::class)->findOne($id_proyecto);
        $ventas = $proyecto->ventas();
        $output = [];
        foreach ($ventas as $venta) {
            $found = false;
            foreach ($output as $v) {
                if ($v->unidad()->descripcion == $venta->unidad()->descripcion) {
                    $found = true;
                    break;
                }
            }
            if (!$found) {
                $output []= $venta;
            }
        }
        return $output;
    }
    protected function startOfYear(DateTimeInterface $up_to)
    {
        return new DateTimeImmutable((clone $up_to)->sub(new DateInterval('P1Y'))->format('31-12-Y'));
    }
    protected function defaultValueDate(DateTimeInterface $up_to, $glosa = '')
    {
        return (object) ['fecha' => $this->startOfYear($up_to), 'valor' => 0, 'glosa' => $glosa, 'estado' => ''];
    }
    protected function extractValueDate(Pago $pago, $glosa = '')
    {
        return (object) ['fecha' => $pago->fecha(), 'valor' => $pago->valor, 'glosa' => $glosa, 'estado' => $pago->estado()->tipo()->descripcion];
    }
    protected function getAnticipos(Venta $venta, DateTimeInterface $up_to)
    {
        if ($venta->pie == 0) {
            return [$this->defaultValueDate($up_to)];
        }
        $cuotas = $venta->pie()->cuotas('fecha', $up_to);
        $ly = $this->startOfYear($up_to);
        $older = array_reduce($cuotas, function($sum, $item) use ($ly) {
            if ($item->pago()->estado()->tipo()->active != 1 or strtolower($item->pago()->estado()->tipo()->descripcion) == 'no pagado') {
                return $sum;
            }
            if ($item->pago()->fecha() >= $ly) {
                return $sum;
            }
            return $sum + $item->pago()->valor;
        });
        $current = array_filter($cuotas, function($item) use ($ly) {
            return $item->pago()->fecha() >= $ly;
        });
        foreach ($current as &$item) {
            $item = $this->extractValueDate($item->pago(), "Cuota {$item->numero}");
        }
        return array_merge([(object) ['fecha' => $ly, 'valor' => $older, 'glosa' => 'Anticipo acumulado', 'estado' => 'Pagado']], $current);
    }
    protected function getReajuste(Venta $venta, DateTimeInterface $up_to)
    {
        if ($venta->pie == 0 or $venta->pie()->reajuste == null) {
            return $this->defaultValueDate($up_to, 'Reajuste');
        }
        return $this->extractValueDate($venta->pie()->reajuste(), 'Reajuste');
    }
    protected function getAbono(Venta $venta, DateTimeInterface $up_to)
    {
        if ($venta->escritura == 0) {
            return $this->defaultValueDate($up_to, 'Abono');
        }
        return $this->extractValueDate($venta->escritura()->pago(), 'Abono');
    }
    protected function getBono(Venta $venta, DateTimeInterface $up_to)
    {
        if ($venta->bono_pie == 0) {
            return $this->defaultValueDate($up_to, 'Bono Pie');
        }
        return $this->extractValueDate($venta->bonoPie()->pago(), 'Bono Pie');
    }
    protected function getCredito(Venta $venta, DateTimeInterface $up_to)
    {
        if ($venta->credito == 0) {
            return $this->defaultValueDate($up_to, 'Credito');
        }
        return $this->extractValueDate($venta->credito()->pago(), 'Credito');
    }
    protected function getSubsidio(Venta $venta, DateTimeInterface $up_to)
    {
        if ($venta->subsidio == 0) {
            return [$this->defaultValueDate($up_to, 'Ahorro'), $this->defaultValueDate($up_to, 'Subsidio')];
        }
        return [$this->extractValueDate($venta->subsidio()->pago(), 'Ahorro'), $this->extractValueDate($venta->subsidio()->subsidio(), 'Subsidio')];
    }
    protected function getResciliacion(Venta $venta, DateTimeInterface $up_to)
    {
        if ($venta->resciliacion == null) {
            return $this->defaultValueDate($up_to, 'Resciliacion');
        }
        return $this->extractValueDate($venta->resciliacion()->pago(), 'Resciliacion');
    }
    protected function getPagos(Venta $venta, DateTimeInterface $up_to)
    {
        $pagos = [];
        $pagos = array_merge($pagos, $this->getAnticipos($venta, $up_to));
        $pagos []= $this->getReajuste($venta, $up_to);
        $pagos []= $this->getAbono($venta, $up_to);
        $pagos []= $this->getBono($venta, $up_to);
        $pagos []= $this->getCredito($venta, $up_to);
        $pagos = array_merge($pagos, $this->getSubsidio($venta, $up_to));
        return array_filter($pagos, function($item) {
            return $item->valor != 0;
        });
    }

    protected function buildLine(Venta $venta, $pago)
    {
        if ($pago->valor > 0) {
            return ['', $venta->unidad()->descripcion, $pago->fecha->format('d/m/Y'), $pago->glosa, '', $pago->valor, $pago->estado];
        }
        return ['', $venta->unidad()->descripcion, $pago->fecha->format('d/m/Y'), $pago->glosa, -$pago->valor, '', $pago->estado];
    }
    protected function buildLibro(Venta $venta, DateTimeInterface $up_to)
    {
        $pagos = $this->getPagos($venta, $up_to);
        $output = [
            ['', "Cuenta: Anticipos Dpto {$venta->unidad()->descripcion}"],
            ['', 'Fecha', 'Glosa', 'Haber', 'Debe', 'Estado']
        ];
        $debe = 0;
        $haber = 0;
        foreach ($pagos as $pago) {
            $output []= $this->buildLine($venta, $pago);
            if ($pago->valor > 0) {
                $debe += $pago->valor;
            }
            else {
                $haber -= $pago->valor;
            }
        }
        $output []= ['', '', '', 'Total', $haber, $debe];
        return $output;
    }

    public function build(int $id_proyecto, DateTimeInterface $up_to)
    {
        ini_set('max_execution_time', 60 * 60);
        $ventas = $this->getVentas($id_proyecto);

        $output = ["Libro Mayor {$ventas[0]->proyecto()->descripcion}", ''];
        foreach ($ventas as $venta) {
            $output = array_merge($output, $this->buildLibro($venta, $up_to));
        }

        $filename = "Contabilidad - Resumen - {$ventas[0]->proyecto()->descripcion} - {$up_to->format('Y-m-d')}.xlsx";
        $informe = new Informe();
        $informe->createSpreadsheet()
            ->addArray($output)
            ->formatColumn('E')
            ->formatColumn('F')
            ->send($filename);
    }
}
