<?php

final class ExtensionStoreReleaseFileTransaction
  extends ExtensionStoreReleaseTransactionType {

  const TRANSACTIONTYPE = 'est:release:file';

  public function generateOldValue($object) {
    return $object->getDownloadFilePHID();
  }

  public function applyInternalEffects($object, $value) {
    $object->setDetail('file-phid', $value);

    $object->setDetail('format', 'phar-file');
    // We might allow different methods of release later.
  }

  public function applyExternalEffects($object, $value) {
    $file_phid = $value;
    PhabricatorFile::attachFileToObject($file_phid, $object->getPHID());
  }

  public function validateTransactions($object, array $xactions) {
    $errors = array();

    if ($this->isEmptyTextTransaction(
        $object->getDownloadFilePHID(), $xactions)) {
      $errors[] = $this->newRequiredError(
        pht('File is required for a release'));
      return $errors;
    }

    if (!$this->isNewObject()) {
      foreach ($xactions as $xaction) {
        $errors[] = $this->newInvalidError(
          pht('Once a release is created, its file can not be changed.'),
          $xaction);
      }
    }

    $viewer = $this->getActor();
    foreach ($xactions as $xaction) {
      $file_phid = $xaction->getNewValue();

      $file = new PhabricatorFileQuery()
        ->setViewer($viewer)
        ->withPHIDs(array($file_phid))
        ->setRaisePolicyExceptions(false)
        ->requireCapabilities(
          array(
            PhabricatorPolicyCapability::CAN_VIEW,
            PhabricatorPolicyCapability::CAN_EDIT, // TODO this didn't
            // actually catch anything. why is that?
          ))
        ->executeOne();

      if (!$file) {
        $errors[] = $this->newInvalidError(
          pht(
            'File "%s" is invalid: the file must exist and you '.
            'must have permission to edit it in order publish it as a '.
            'release.',
            $file_phid),
          $xaction);
        continue;
      }

      // TODO validate:
      // that it's a PHAR file, at least by name + mimetype
      // that it's internal phutilname matches the config
      // maybe do that offline

    }

    return $errors;
  }

}
