<?php

namespace Drupal\acquia_contenthub\Plugin\FileSchemeHandler;

use Acquia\ContentHubClient\CDF\CDFObjectInterface;
use Drupal\acquia_contenthub\Exception\ContentHubFileException;
use Drupal\Core\File\FileSystemInterface;

/**
 * Contains common functions to handle file syndication.
 *
 * Exceptions are handled in the File event subscriber.
 *
 * @see \Drupal\acquia_contenthub_subscriber\EventSubscriber\ParseCdf\File
 */
trait FileHandlerTrait {

  /**
   * The file system.
   *
   * @var \Drupal\Core\File\FileSystemInterface
   */
  protected $fileSystem;

  /**
   * Validates if the necessary attributes are in the CDF.
   *
   * @param \Acquia\ContentHubClient\CDF\CDFObjectInterface $object
   *   The CDF object.
   *
   * @throws \Drupal\acquia_contenthub\Exception\ContentHubFileException
   */
  public function validateAttributes(CDFObjectInterface $object): void {
    if (!$object->getAttribute('file_location')) {
      throw new ContentHubFileException(
        'file_location is missing from file CDF',
        ContentHubFileException::MISSING_ATTRIBUTE,
        $object->getUuid(),
      );
    }

    if (!$object->getAttribute('file_uri')) {
      throw new ContentHubFileException(
        'file_uri is missing from file CDF',
        ContentHubFileException::MISSING_ATTRIBUTE,
        $object->getUuid(),
      );
    }
  }

  /**
   * Checks the target directory if it exists and is writable.
   *
   * @param string $uri
   *   The uri of the file.
   * @param string $file_uuid
   *   The uuid of the file.
   *
   * @throws \Drupal\acquia_contenthub\Exception\ContentHubFileException
   */
  public function validateDirectory(string $uri, string $file_uuid) {
    $dirname = $this->fileSystem()->dirname($uri);
    $res = $this->fileSystem()
      ->prepareDirectory($dirname, FileSystemInterface::CREATE_DIRECTORY);
    if ($res) {
      return;
    }

    throw new ContentHubFileException(
      sprintf('target directory (%s) does not exist or not writable', $dirname),
      ContentHubFileException::DIRECTORY_NOT_WRITABLE,
      $file_uuid,
    );
  }

  /**
   * Save the data to file system.
   *
   * @param string $data
   *   Data to save.
   * @param string $destination
   *   Destination of data.
   * @param int $replace
   *   Replacement option.
   *
   * @return bool|string
   *   String saved or bool if failed.
   */
  public function saveData(string $data, string $destination, int $replace) {
    return $this->fileSystem()->saveData($data, $destination, $replace);
  }

  /**
   * Returns a FileSystemInterface object.
   *
   * @return \Drupal\Core\File\FileSystemInterface
   *   The fs service.
   */
  public function fileSystem(): FileSystemInterface {
    if ($this->fileSystem) {
      return $this->fileSystem;
    }
    return $this->fileSystem = \Drupal::service('file_system');
  }

  /**
   * Sets the file system service.
   *
   * Comply to the dependency injection pattern.
   *
   * @param \Drupal\Core\File\FileSystemInterface $fs
   *   The file system service.
   */
  public function setFileSystem(FileSystemInterface $fs): void {
    $this->fileSystem = $fs;
  }

}
