<?php

final class ExtensionStoreExtension extends ExtensionStoreDAO
  implements
    PhabricatorPolicyInterface,
    PhabricatorApplicationTransactionInterface,
    PhabricatorSubscribableInterface,
    PhabricatorFlaggableInterface,
    // PhabricatorFerretInterface,
    // PhabricatorFulltextInterface,
    PhabricatorMentionableInterface,
  //   PhabricatorConduitResultInterface,
  //   PhabricatorCustomFieldInterface,
    PhabricatorDestructibleInterface {

  protected $publisherPHID;
  private $publisher = self::ATTACHABLE;

  private $latestRelease = self::ATTACHABLE; // TODO

  protected $name;
  protected $extensionKey;
  protected $status = ExtensionStoreExtensionStatus::STATUS_ACTIVE;
  protected $category = 'server'; // one of the [server (phorge), client (arc), library]
  protected $description;
  protected $details = array();

  public static function initializeNewExtension(PhabricatorUser $actor) {
    // TODO Packages uses this place to set view/edit policies
    return new self();
  }

  public function attachPublisher(ExtensionStorePublisher $publisher) {
    $this->publisher = $publisher;
    if ($publisher) {
      $this->publisherPHID = $publisher->getPHID();
    }
    return $this;
  }

  public function getPublisher() {
    return $this->assertAttached($this->publisher);
  }

  public function attachLatestRelease(?ExtensionStoreRelease $release) {
    $this->latestRelease = $release;
    return $this;
  }

  public function getLatestRelease() {
    return $this->assertAttached($this->latestRelease);
  }

  public function getFullExtensionKey() {
    $publisher = $this->getPublisher();
    return $publisher->getPublisherKey().'.'.$this->getExtensionKey();
  }

  public function setDetail($key, $value) {
    $this->details[$key] = $value;
    return $this;
  }

  public function getDetail($key) {
    return idx($this->details, $key);
  }

  public function setPhutilLibName($libname) {
    return $this->setDetail('libphutilname', $libname);
  }


  public function getPhutilLibName() {
    return $this->getDetail('libphutilname');
  }


  protected function getConfiguration() {
    return array(
      self::CONFIG_AUX_PHID => true,
      self::CONFIG_SERIALIZATION => array(
        'details' => self::SERIALIZATION_JSON,
      ),
      self::CONFIG_COLUMN_SCHEMA => array(
        'name' => 'sort255',
        'extensionKey' => 'sort64',
        'status' => 'text32',
        'category' => 'text32',
        'description' => 'text',
      ),
      self::CONFIG_KEY_SCHEMA => array(
        'key_publisher' => array(
          'unique' => false,
          'columns' => array('publisherPHID'),
        ),
        'key_extensionkey' => array(
          'unique' => true,
          'columns' => array('extensionKey'),
        ),
        'key_category' => array(
          'unique' => false,
          'columns' => array('category'),
        ),
      ),
    ) + parent::getConfiguration();
  }


  public function getPHIDType() {
    return ExtensionStoreExtensionPHIDType::TYPECONST;
  }

  public function getURI() {
    $id = $this->getID();
    return "/extensionstore/extension/{$id}";
  }

  public function isArchived() {
    if ($this->publisher !== self::ATTACHABLE &&
        $this->publisher->isArchived()) {
      return true;
    }
    return $this->status == ExtensionStoreExtensionStatus::STATUS_ARCHIVED;
  }

  public function toExtensionQueryResult(PhabricatorUser $viewer) {
    $release = $this->getLatestRelease();
    if (!$release) {
      return null;
    }
    $file_phid = $release->getDownloadFilePHID();

    /** @var PhabricatorFile file */
    $file = new PhabricatorObjectQuery()
      ->setViewer($viewer)
      ->withPHIDs(array(PhabricatorFileFilePHIDType::TYPECONST))
      ->withPHIDs(array($file_phid))
      ->executeOne();

    return new ExtensionQueryResult()
      ->setExtensionKey($this->getFullExtensionKey())
      ->setPhutilLibName($this->getPhutilLibName())
      ->setVersion($release->getName())
      ->setFormat('phar-file')
      ->setDownloadUri($file->getDownloadURI());
  }

/* -(  PhabricatorPolicyInterface  )----------------------------------------- */

  public function getCapabilities() {
    return array(
      PhabricatorPolicyCapability::CAN_VIEW,
      PhabricatorPolicyCapability::CAN_EDIT,
      // CAN_PUBLISH
    );
  }

  public function getPolicy($capability) {
    switch ($capability) {
      case PhabricatorPolicyCapability::CAN_VIEW:
        return PhabricatorPolicies::POLICY_PUBLIC;
    }
    // TODO
    return PhabricatorPolicies::POLICY_ADMIN;
  }

  public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
    return false;
  }

/* -(  PhabricatorApplicationTransactionInterface  )------------------------- */


  public function getApplicationTransactionEditor() {
    return new ExtensionStoreExtensionTransactionEditor();
  }

  public function getApplicationTransactionTemplate() {
    return new ExtensionStoreExtensionTransaction();
  }

/* -(  PhabricatorSubscribableInterface  )----------------------------------- */

  public function isAutomaticallySubscribed($phid) {
    return false;
  }


/* -(  PhabricatorDestructibleInterface  )----------------------------------- */

  public function destroyObjectPermanently(
    PhabricatorDestructionEngine $engine) {

    $this->openTransaction();
      $this->delete();
    $this->saveTransaction();

  }


}
