<?php
namespace Incoviba\Service\Venta;

use PDO;
use PDOException;
use Psr\Log\LoggerInterface;
use Incoviba\Common\Define;
use Incoviba\Common\Ideal\Service;
use Incoviba\Common\Implement\Exception\EmptyResult;
use Incoviba\Exception;
use Incoviba\Repository;
use Incoviba\Model;

class Propiedad extends Service
{
    public function __construct(
        LoggerInterface $logger,
        protected Repository\Venta\Propiedad $propiedadRepository,
        protected Repository\Venta\Unidad $unidadRepository,
        protected Define\Connection $connection
    ) {
        parent::__construct($logger);
    }

    /**
     * @param int $propiedad_id
     * @return Model\Venta\Propiedad
     * @throws Exception\ServiceAction\Read
     */
    public function getById(int $propiedad_id): Model\Venta\Propiedad
    {
        try {
            return $this->process($this->propiedadRepository->fetchById($propiedad_id));
        } catch (EmptyResult $exception) {
            throw new Exception\ServiceAction\Read(__CLASS__, $exception);
        }
    }

    /**
     * @param int $propiedad_id
     * @return array
     * @throws Exception\ServiceAction\Read
     */
    public function getArrayById(int $propiedad_id): array
    {
        try {
            return $this->propiedadRepository->fetchArrayById($propiedad_id);
        } catch (EmptyResult $exception) {
            throw new Exception\ServiceAction\Read(__CLASS__, $exception);
        }
    }
    public function addPropiedad(array $ids): Model\Venta\Propiedad
    {
        $unidades = [];
        foreach ($ids as $unidad_id) {
            $unidades []= $this->unidadRepository->fetchById($unidad_id);
        }
        usort($unidades, function(Model\Venta\Unidad $a, Model\Venta\Unidad $b) {
            $t = $a->proyectoTipoUnidad->tipoUnidad->orden - $b->proyectoTipoUnidad->tipoUnidad->orden;
            if ($t === 0) {
                return strcmp(str_pad($a->descripcion, 4, '0', STR_PAD_LEFT), str_pad($b->descripcion, 4, '0', STR_PAD_LEFT));
            }
            return $t;
        });
        try {
            $propiedad = $this->propiedadRepository->fetchVigenteByUnidad($unidades[0]->id);
            $propiedad = $this->propiedadRepository->edit($propiedad, ['unidad_principal' => $unidades[0]->id]);
        } catch (EmptyResult) {
            $propiedad = $this->propiedadRepository->create([
                'unidad_principal' => $unidades[0]->id,
                'estado' => 1
            ]);
            $propiedad = $this->propiedadRepository->save($propiedad);
        }
        $this->addUnidades($propiedad, $unidades);
        $this->cleanUpUnidades($propiedad, $unidades);

        return $propiedad;
    }
    protected function addUnidades(Model\Venta\Propiedad $propiedad, array $unidades): void
    {
        $query = "SELECT 1 FROM `propiedad_unidad` WHERE `propiedad` = ? AND `unidad` = ?";
        $statement = $this->connection->prepare($query);
        $query2 = "INSERT INTO `propiedad_unidad` (`propiedad`, `unidad`, `principal`) VALUES (?, ?, ?)";
        $insert = $this->connection->prepare($query2);
        foreach ($unidades as $ix => $unidad) {
            try {
                $statement->execute([$propiedad->id, $unidad->id]);
                $result = $statement->fetch(PDO::FETCH_ASSOC);
                if (!$result) {
                    throw new EmptyResult($query);
                }
            } catch (PDOException|EmptyResult) {
                $insert->execute([$propiedad->id, $unidad->id, ($ix === 0) ? 1 : 0]);
            }
        }
    }
    protected function cleanUpUnidades(Model\Venta\Propiedad $propiedad, array $unidades): void
    {
        $query = "SELECT `unidad` FROM `propiedad_unidad` WHERE `propiedad` = ?";
        $statement = $this->connection->prepare($query);
        $statement->execute([$propiedad->id]);
        $results = $statement->fetchAll(PDO::FETCH_ASSOC);

        if (!$results) {
            return;
        }

        $all_ids = array_map(function($row) {return $row['unidad'];}, $results);
        $new_ids = array_map(function(Model\Venta\Unidad $unidad) {return $unidad->id;}, $unidades);
        $diff = array_diff($all_ids, $new_ids);
        if (count($diff) === 0) {
            return;
        }
        $query = "DELETE FROM `propiedad_unidad` WHERE `propiedad` = ? AND `unidad` = ?";
        $statement = $this->connection->prepare($query);
        foreach ($diff as $id) {
            $statement->execute([$propiedad->id, $id]);
        }
    }
    protected function process(Model\Venta\Propiedad $propiedad): Model\Venta\Propiedad
    {
        return $propiedad;
    }
}
