<?php

declare(strict_types=1);

namespace Drupal\languagewire_translation_provider\Adapter\Database;

use Drupal\Core\Database\Connection;
use Drupal\languagewire_translation_provider\Adapter\TMGMT\TmgmtTranslatorInterface;
use Drupal\languagewire_translation_provider\Database\Mapper\ProjectTemplateMapper;
use Drupal\languagewire_translation_provider\Database\ProjectTemplateRepositoryInterface;
use Drupal\languagewire_translation_provider\Database\TablesInterface;
use Drupal\languagewire_translation_provider\Domain\ProjectTemplate;

/**
 * Drupal Project Template Repository.
* */
final class ProjectTemplateRepository implements ProjectTemplateRepositoryInterface {

  /**
   * Connection.
   *
   * @var \Drupal\Core\Database\Connection
   */
  private Connection $connection;

  /**
   * Mapper.
   *
   * @var \Drupal\languagewire_translation_provider\Database\Mapper\ProjectTemplateMapper
   */
  private ProjectTemplateMapper $mapper;

  /**
   * Constructs a new ProjectTemplateRepository object.
   *
   * @param \Drupal\Core\Database\Connection $connection
   *   Connection.
   * @param \Drupal\languagewire_translation_provider\Database\Mapper\ProjectTemplateMapper $mapper
   *   Mapper.
   */
  public function __construct(Connection $connection, ProjectTemplateMapper $mapper) {
    $this->connection = $connection;
    $this->mapper = $mapper;
  }

  /**
   * Get by ID.
   *
   * @throws \Exception
   */
  public function getById(int $projectTemplateId): ?ProjectTemplate {
    $dbItem = $this->connection->select(TablesInterface::PROJECT_TEMPLATES, 'project_templates')
      ->fields('project_templates')
      ->condition('template_id', $projectTemplateId)
      ->execute()
      ->fetchAssoc();
    return $dbItem ? $this->mapper->toProjectTemplate($dbItem) : NULL;
  }

  /**
   * Get by platform ID.
   *
   * @throws \Exception
   */
  public function getByPlatformId(int $projectTemplatePlatformId, TmgmtTranslatorInterface $translator): ?ProjectTemplate {
    $dbItem = $this->connection->select(TablesInterface::PROJECT_TEMPLATES, 'project_templates')
      ->fields('project_templates')
      ->condition('server_id', $projectTemplatePlatformId)
      ->condition('translator_id', $translator->id())
      ->execute()
      ->fetchAssoc();
    return $dbItem ? $this->mapper->toProjectTemplate($dbItem) : NULL;
  }

  /**
   * Get all.
   *
   * @throws \Exception
   */
  public function getAll(TmgmtTranslatorInterface $translator): array {
    $dbItems = $this->connection->select(TablesInterface::PROJECT_TEMPLATES, 'project_templates')
      ->fields('project_templates')
      ->condition('translator_id', $translator->id())
      ->execute()
      ->fetchAll(\PDO::FETCH_ASSOC);
    $projectTemplates = array_map(function (array $dbItem): ?ProjectTemplate {
      return $this->mapper->toProjectTemplate($dbItem);
    }, $dbItems);
    return array_filter($projectTemplates);
  }

  /**
   * {@inheritDoc}
   *
   * @throws \Exception
   */
  public function save(ProjectTemplate $projectTemplate, TmgmtTranslatorInterface $translator): void {
    $projectTemplate->getTemplateId() ? $this->update($projectTemplate, $translator) : $this->insert($projectTemplate, $translator);
  }

  /**
   * {@inheritDoc}
   *
   * @throws \Exception
   */
  public function saveAll(array $projectTemplates, TmgmtTranslatorInterface $translator): void {
    foreach ($projectTemplates as $projectTemplate) {
      $this->save($projectTemplate, $translator);
    }
  }

  /**
   * {@inheritDoc}
   *
   * @throws \Exception
   */
  public function removeAll(TmgmtTranslatorInterface $translator): void {
    $this->connection->delete(TablesInterface::PROJECT_TEMPLATES)
      ->condition('translator_id', $translator->id())
      ->execute();
  }

  /**
   * Insert project template.
   *
   * @throws \Exception
   */
  private function insert(ProjectTemplate $projectTemplate, TmgmtTranslatorInterface $translator): void {
    $dbEntity = $this->mapper->toDatabaseEntity($projectTemplate, $translator);
    $this->connection->insert(TablesInterface::PROJECT_TEMPLATES)
      ->fields(array_keys($dbEntity))
      ->values(array_values($dbEntity))
      ->execute();
  }

  /**
   * Update project template.
   *
   * @throws \Exception
   */
  private function update(ProjectTemplate $projectTemplate, TmgmtTranslatorInterface $translator): void {
    $this->connection->update(TablesInterface::PROJECT_TEMPLATES)
      ->condition('pid', $projectTemplate->getTemplateId())
      ->fields($this->mapper->toDatabaseEntity($projectTemplate, $translator))
      ->execute();
  }

}
