<?php
namespace Incoviba\Service;

use DateTimeInterface;
use DateTimeImmutable;
use DateInterval;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\UploadedFileInterface;
use Psr\Log\LoggerInterface;
use Incoviba\Common\Ideal\Service;
use Incoviba\Common\Define\Cartola\Banco;
use Incoviba\Common\Define\Contabilidad\Exporter;
use Incoviba\Common\Implement\Exception;
use Incoviba\Model;
use Incoviba\Repository;

class Cartola extends Service
{
    public function __construct(LoggerInterface $logger,
                                protected StreamFactoryInterface $streamFactory, protected Exporter $exporter,
                                protected Repository\Inmobiliaria $inmobiliariaRepository,
                                protected Repository\Inmobiliaria\Cuenta $cuentaRepository,
                                protected Repository\Movimiento $movimientoRepository,
                                protected Movimiento $movimientoService,
                                protected Repository\Cartola $cartolaRepository) {
        parent::__construct($logger);
    }

    protected array $bancos;
    public function register(string $name, Banco $banco): Cartola
    {
        $this->bancos[$name] = $banco;
        return $this;
    }
    public function process(Model\Inmobiliaria $inmobiliaria, Model\Banco $banco, DateTimeInterface $mes, UploadedFileInterface $file): array
    {
        return $this->bancos[strtolower($banco->nombre)]->process($file);
    }
    public function export(Model\Inmobiliaria $inmobiliaria, Model\Banco $banco, DateTimeInterface $mes, array $movimientos): string
    {
        return $this->exporter->export($inmobiliaria, $banco, $mes, $movimientos);
    }
    public function diaria(Model\Inmobiliaria\Cuenta $cuenta, DateTimeInterface $fecha, UploadedFileInterface $file): array
    {
        $ms = $this->getMovimientosDiarios($cuenta->banco, $file);

        $cartolaData = [
            'cargos' => 0,
            'abonos' => 0,
            'saldo' => 0
        ];
        $movimientos = [];
        foreach ($ms as $m) {
            $movimiento = $this->buildMovimiento($cuenta, $m);
            $movimiento = $this->movimientoService->process($movimiento);

            if ($movimiento->fecha->getTimestamp() === $fecha->getTimestamp()) {
                $movimientos []= $movimiento;
                $cartolaData['cargos'] += $movimiento->cargo;
                $cartolaData['abonos'] += $movimiento->abono;
            }
            if ($movimiento->fecha->getTimestamp() > $fecha->getTimestamp()) {
                continue;
            }
            $cartolaData['saldo'] = $movimiento->saldo;
        }
        $cartola = $this->buildCartola($cuenta, $fecha, $cartolaData);
        return compact('cartola', 'movimientos');
    }
    public function diariaManual(Model\Inmobiliaria\Cuenta $cuenta, DateTimeInterface $fecha, array $data): array
    {
        $cartolaData = [
            'cargos' => 0,
            'abonos' => 0,
            'saldos' => 0
        ];
        $movimientos = [];
        foreach ($data as $row) {
            $dataMovimiento = $row;
            $dataMovimiento['fecha'] = $fecha->format('Y-m-d');
            $dataMovimiento['documento'] = '';
            $movimiento = $this->buildMovimiento($cuenta, $dataMovimiento);
            $movimiento = $this->movimientoService->process($movimiento);

            $movimientos []= $movimiento;
            $cartolaData['cargos'] += $movimiento->cargo;
            $cartolaData['abonos'] += $movimiento->abono;
            $cartolaData['saldo'] = $movimiento->saldo;
        }
        $cartola = $this->buildCartola($cuenta, $fecha, $cartolaData);
        return compact('cartola', 'movimientos');
    }

    protected function getMovimientosDiarios(Model\Banco $banco, UploadedFileInterface $file): array
    {
        $movimientos = $this->bancos[strtolower($banco->nombre)]->process($file);
        return $this->bancos[strtolower($banco->nombre)]->processMovimientosDiarios($movimientos);
    }
    protected function buildCartola(Model\Inmobiliaria\Cuenta $cuenta, DateTimeInterface $fecha, array $data): Model\Cartola
    {
        try {
            return $this->cartolaRepository->fetchByCuentaAndFecha($cuenta->id, $fecha);
        } catch (Exception\EmptyResult) {
            $data['cuenta_id'] = $cuenta->id;
            $data['fecha'] = $fecha->format('Y-m-d');
            $cartola = $this->cartolaRepository->create($data);
            return $this->cartolaRepository->save($cartola);
        }
    }
    protected function buildMovimiento(Model\Inmobiliaria\Cuenta $cuenta, array $data): Model\Movimiento
    {
        try {
            return $this->movimientoRepository
                ->fetchByCuentaAndFechaAndCargoAndAbonoAndSaldo(
                    $cuenta->id,
                    new DateTimeImmutable($data['fecha']),
                    $data['cargo'] ?? 0,
                    $data['abono'] ?? 0,
                    $data['saldo']
                );
        } catch (Exception\EmptyResult $exception) {
            $data['cuenta_id'] = $cuenta->id;
            $movimiento = $this->movimientoRepository->create($data);
            return $this->movimientoRepository->save($movimiento);
        }
    }
}
