<?php
namespace Incoviba\Service;

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

class Persona extends Ideal\Service
{
    public function __construct(LoggerInterface $logger,
                                protected Repository\Persona $personaRepository,
                                protected Repository\Persona\Datos $datosPersonaRepository,
                                protected Repository\Venta\Propietario $propietarioRepository)
    {
        parent::__construct($logger);
    }

    /**
     * @param int $rut
     * @return Model\Persona
     * @throws Read
     */
    public function getById(int $rut): Model\Persona
    {
        try {
            return $this->process($this->personaRepository->fetchById($rut));
        } catch (Implement\Exception\EmptyResult $exception) {
            throw new Read(__CLASS__, $exception);
        }
    }
    public function add(array $data): Model\Persona
    {
        try {
            $persona = $this->personaRepository->fetchById($data['rut']);
        } catch (Implement\Exception\EmptyResult) {
            try {
                $propietario = $this->propietarioRepository->fetchById($data['rut']);
                $data['nombres'] = $propietario->nombres;
                $data['apellido_paterno'] = $propietario->apellidos['paterno'];
                $data['apellido_materno'] = $propietario->apellidos['materno'];
                $data['direccion_id'] = $propietario->datos->direccion->id;
            } catch (Implement\Exception\EmptyResult) {}
            $persona = $this->personaRepository->create($data);
            $persona = $this->personaRepository->save($persona);
        }
        if (isset($data['direccion_id']) or isset($data['email']) or isset($data['telefono'])) {
            $datosData = ['persona_rut' => $persona->rut];
            if (isset($data['direccion_id'])) {
                $datosData['direccion_id'] = $data['direccion_id'];
            }
            if (isset($data['email'])) {
                $datosData['email'] = $data['email'];
            }
            if (isset($data['telefono'])) {
                $datosData['telefono'] = $data['telefono'];
            }
            try {
                $datos = $this->datosPersonaRepository->fetchByPersona($persona->rut);
                $this->datosPersonaRepository->edit($datos, $data);
            } catch (Implement\Exception\EmptyResult) {
                $datos = $this->datosPersonaRepository->create($datosData);
                $this->datosPersonaRepository->save($datos);
            }
        }
        return $this->process($persona);
    }
    public function edit(Model\Persona $persona, array $data): Model\Persona
    {
        $filteredData = $this->personaRepository->filterData($data);
        try {
            $datosData = $this->datosPersonaRepository->filterData($data);
            $this->datosPersonaRepository->edit($persona->datos(), $datosData);
            return $this->personaRepository->edit($persona, $filteredData);
        } catch (Implement\Exception\EmptyResult) {
            return $persona;
        }
    }

    protected function process(Model\Persona $persona): Model\Persona
    {
        $persona->addFactory('datos', (new Implement\Repository\Factory())
            ->setCallable([$this->datosPersonaRepository, 'fetchByPersona'])
            ->setArgs(['persona_rut' => $persona->rut]));
        return $persona;
    }
}
