<?php

declare(strict_types=1);

namespace Gls\GlsPoland\PrestaShop\ObjectModel;

final class Persistence implements PersistenceInterface
{
    private $db;

    public function __construct(?\Db $db = null)
    {
        $this->db = $db ?? \Db::getInstance();
    }

    public function save(\ObjectModel $model): void
    {
        $id = (int) $model->id;

        $result = $this->execute(function () use ($model): bool {
            return $model->validateFields()
                && $model->validateFieldsLang()
                && $model->save();
        });

        if (!$result) {
            $message = 0 >= $id
                ? sprintf('Failed to create a new %s.', $model->getObjectName())
                : sprintf('Failed to update %s ID %d.', $model->getObjectName(), $id);

            throw new \RuntimeException($message);
        }
    }

    public function delete(\ObjectModel $model): void
    {
        if (0 >= (int) $model->id) {
            return;
        }

        $result = $this->execute(function () use ($model): bool {
            return $model->delete();
        });

        if (!$result) {
            throw new \RuntimeException(sprintf('Failed to delete %s ID %d.', $model->getObjectName(), $model->id));
        }
    }

    /**
     * {@inheritdoc}
     */
    public function execute(\Closure $closure): bool
    {
        if ($closure()) {
            return true;
        }

        if (!$error = $this->db->getNumberError()) {
            return false;
        }

        throw new \PrestaShopDatabaseException($this->db->getMsgError(), $error);
    }
}
