<?php
namespace Incoviba\Service\Contabilidad\Informe\Tesoreria\Input\Data;

use Exception;
use Psr\Log\LoggerInterface;
use Incoviba\Common\Ideal;
use Incoviba\Common\Implement;
use Incoviba\Repository;

class SaldosContables extends Ideal\Service
{
    public function __construct(LoggerInterface $logger,
                                protected Repository\Inmobiliaria $inmobiliariaRepository,
                                protected Repository\Inmobiliaria\Cuenta $cuentaRepository,
                                protected Repository\Contabilidad\Banco $bancoRepository,
                                protected Repository\Contabilidad\Movimiento $movimientoRepository,
                                protected Repository\Contabilidad\Movimiento\Detalle $detalleRepository)
    {
        parent::__construct($logger);
    }

    public function load(array $data): void
    {
        $this->data = $data['movimientos'];
        foreach ($data['movimientos'] as $type => $dataMovimiento) {
            switch ($type) {
                case 'total':
                    $this->saldoInicial = $dataMovimiento;
                    break;
                case 'depositos':
                    $this->loadDepositos($dataMovimiento);
                    break;
                case 'egresos':
                case 'ingresos':
                    $this->loadMovimiento($dataMovimiento);
                    break;
            }
        }
    }

    protected array $sociedades;
    protected int $saldoInicial;
    protected array $data;

    protected function loadDepositos(array $data): void
    {
        $this->logger->error('Cargando depositos', $data);
    }
    protected function loadMovimiento(array $data): void
    {
        $sociedades = $this->getSociedades();
        $unmatched = [];
        foreach ($data as $dataMovimiento) {
            try {
                $sociedad_rut = $this->matchSociedad($sociedades, $dataMovimiento->empresa);
                $banco = $this->bancoRepository->fetchByNombre($dataMovimiento->banco);
                $cuenta = $this->cuentaRepository->fetchByInmobiliariaAndBanco($sociedad_rut, $banco->id);
                $data = [
                    'cuenta_id' => $cuenta->id,
                    'fecha' => $dataMovimiento->fecha->format('Y-m-d'),
                    'glosa' => mb_convert_encoding($dataMovimiento->{'descripción'}, 'UTF-8'),
                    'documento' => $dataMovimiento->{'n°Doc'},
                    'cargo' => -$dataMovimiento->egresos,
                    'abono' => $dataMovimiento->ingresos,
                    'saldo' => $this->getSaldo($dataMovimiento)
                ];
                try {
                    $movimiento = $this->movimientoRepository->fetchByCuentaAndFechaAndGlosaAndCargoAndAbonoAndSaldo($cuenta->id, $dataMovimiento->fecha, $data['glosa'], $data['cargo'], $data['abono'], $data['saldo']);
                } catch (Implement\Exception\EmptyResult) {
                    $movimiento = $this->movimientoRepository->create($data);
                    $movimiento = $this->movimientoRepository->save($movimiento);
                }
                list($rut, $digito) = explode('-', $dataMovimiento->rut);
                $data = [
                    'movimiento_id' => $movimiento->id,
                    'centro_costo_id' => $dataMovimiento->cc,
                    'rut' => (int) preg_replace('/\D*/', '', $rut),
                    'digito' => $digito,
                    'nombre' => $dataMovimiento->nombres,
                    'categoria' => $dataMovimiento->categoria,
                    'detalle' => $dataMovimiento->detalle,
                ];
                if ($data['centro_costo_id'] === 0 and ($data['rut'] === 0 or $data['nombre'] === '' or $data['categoria'] === '' or $data['detalle'] === '')) {
                    continue;
                }
                try {
                    $detalles = $this->detalleRepository->fetchByMovimiento($movimiento->id);
                    $this->detalleRepository->edit($detalles, $data);
                } catch (Implement\Exception\EmptyResult) {
                    $detalles = $this->detalleRepository->create($data);
                    $this->detalleRepository->save($detalles);
                }
            } catch (Exception $exception) {
                $this->logger->error($exception);
                $unmatched []= $dataMovimiento;
            }
        }

        if (count($unmatched) > 0) {
            $this->logger->error('Movimientos no asociados', $unmatched);
        }
    }

    protected function getSociedades(): array
    {
        if (!isset($this->sociedades)) {
            $this->sociedades = [];
            try {
                $this->sociedades = $this->inmobiliariaRepository->fetchAll();
            } catch (Implement\Exception\EmptyResult $e) {
                $this->logger->error($e->getMessage());
            }
        }
        return $this->sociedades;
    }
    protected function getSaldo($movimiento): int
    {
        $saldo = $this->saldoInicial;
        foreach ($this->data as $type => $dataMovimientos) {
            if (in_array($type, ['total', 'depositos'])) {
                continue;
            }
            foreach ($dataMovimientos as $dataMovimiento) {
                if ($dataMovimiento !== $movimiento) {
                    continue;
                }
                $saldo += $dataMovimiento->ingresos + $dataMovimiento->egresos;
            }
        }
        return $saldo;
    }
    protected function matchSociedad(array $sociedades, string $name): int
    {
        foreach ($sociedades as $sociedad) {
            $abreviacion = $sociedad->abreviacion;
            if ($abreviacion === 'Incoviba') {
                if (preg_match('/(Vial Balmaceda)+/', $name) === 1) {
                    return $sociedad->rut;
                }
                continue;
            }
            if (str_contains($abreviacion, 'Optimus')) {
                $abreviacion = 'Óptimus';
            }
            if (preg_match("/({$abreviacion})+/", $name) === 1) {
                return $sociedad->rut;
            }
        }

        throw new Exception("No se encontró la sociedad asociada al nombre '{$name}'");
    }
}
