<?php
namespace Incoviba\Service\Venta;

use DateTimeInterface;
use Psr\Log\LoggerInterface;
use Incoviba\Common\Ideal;
use Incoviba\Common\Implement;
use Incoviba\Model;
use Incoviba\Repository;
use Incoviba\Service;

class Factura extends Ideal\Service
{
    public function __construct(LoggerInterface $logger,
                                protected Repository\Venta\Factura $facturaRepository,
                                protected Repository\Venta\Factura\Estado $estadoRepository,
                                protected Repository\Venta\Factura\Estado\Tipo $tipoRepository,
                                protected Service\Persona $personaService)
    {
        parent::__construct($logger);
    }

    public function getAll(null|string|array $orderBy = null): array
    {
        try {
            return array_map([$this, 'process'], $this->facturaRepository->fetchAll($orderBy));
        } catch (Implement\Exception\EmptyResult) {
            return [];
        }
    }
    public function getByVenta(int $venta_id): array
    {
        try {
            return array_map([$this, 'process'], $this->facturaRepository->fetchByVenta($venta_id));
        } catch (Implement\Exception\EmptyResult) {
            return [];
        }
    }
    public function getById(int $factura_id): ?Model\Venta\Factura
    {
        try {
            return $this->process($this->facturaRepository->fetchById($factura_id));
        } catch (Implement\Exception\EmptyResult) {
            return null;
        }
    }
    public function getByVentaAndIndex(int $venta_id, int $index): ?Model\Venta\Factura
    {
        try {
            return $this->process($this->facturaRepository->fetchByVentaAndIndex($venta_id, $index));
        } catch (Implement\Exception\EmptyResult) {
            return null;
        }
    }

    public function add(array $data): Model\Venta\Factura
    {
        $factura = $this->getByVentaAndIndex($data['venta_id'], $data['index']);
        if ($factura !== null) {
            return $factura;
        }
        list($data['cliente']['rut'], $data['cliente']['digito']) = explode('-', $data['cliente']['rut']);
        $data['cliente']['rut'] = (int) str_replace('.', '', $data['cliente']['rut']);
        $client = $this->personaService->add($data['cliente']);
        $data['cliente_rut'] = $client->rut;
        unset($data['cliente']);
        $factura = $this->facturaRepository->create($data);
        $factura = $this->facturaRepository->save($factura);
        $tipo = $this->tipoRepository->fetchByDescripcion('generada');
        $this->estadoRepository->save($this->estadoRepository->create([
            'factura_id' => $factura->id,
            'tipo_id' => $tipo->id,
            'fecha' => $factura->fecha
        ]));
        return $this->process($factura);
    }
    public function aprobar(int $factura_id, DateTimeInterface $fecha): ?Model\Venta\Factura
    {
        try {
            $factura = $this->facturaRepository->fetchById($factura_id);
            $tipo = $this->tipoRepository->fetchByDescripcion('aprobada');
            $this->estadoRepository->save($this->estadoRepository->create([
                'factura_id' => $factura->id,
                'tipo_id' => $tipo->id,
                'fecha' => $fecha->format('Y-m-d')
            ]));
            return $this->process($factura);
        } catch (Implement\Exception\EmptyResult) {
            $this->logger->error('Error al aprobar factura', ['factura_id' => $factura_id]);
            return null;
        }
    }

    protected function process(Model\Venta\Factura $factura): Model\Venta\Factura
    {
        $factura->addFactory('estados', (new Implement\Repository\Factory())
            ->setCallable(function($factura_id) {
                return $this->estadoRepository->fetchByFactura($factura_id);
            })
            ->setArgs(['factura_id' => $factura->id]));
        return $factura;
    }
}
