<?php

namespace LakeDrops\DorgFlow;

use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\Script\Event;
use GitElephant\Repository;
use LakeDrops\Component\Dotenv\Dotenv;
use Symfony\Component\Filesystem\Filesystem;

/**
 * Class Handler.
 *
 * @package LakeDrops\DorgFlow
 */
class Handler {

  /**
   * The composer object of this session.
   *
   * @var \Composer\Composer
   */
  protected $composer;

  /**
   * The input-output object of the composer session.
   *
   * @var \Composer\IO\IOInterface
   */
  protected $io;

  /**
   * Handler constructor.
   *
   * @param \Composer\Composer $composer
   *   The composer object of this session.
   * @param \Composer\IO\IOInterface $io
   *   The input-output object of the composer session.
   */
  public function __construct(Composer $composer, IOInterface $io) {
    $this->composer = $composer;
    $this->io = $io;
  }

  /**
   * Retrieve a package from the current composer process.
   *
   * @param string $name
   *   Name of the package to get from the current composer installation.
   *
   * @return \Composer\Package\PackageInterface
   *   The package.
   */
  protected function getPackage($name) {
    return $this->composer->getRepositoryManager()->getLocalRepository()->findPackage($name, '*');
  }

  /**
   * Post install/update event to prepare projects for development.
   *
   * @param \Composer\Script\Event $event
   *   The event that triggered the call of this function.
   */
  public function prepareDevProjects(Event $event) {

    // We only do the fancy stuff for developers.
    if (!$event->isDevMode()) {
      return;
    }

    $options = $this->getOptions();
    if (empty($options['projects'])) {
      return;
    }

    $this->io->write('Dorgflow: Preparing drupol.org packages for development', TRUE);
    $installationManager = $this->composer->getInstallationManager();
    foreach ($options['projects'] as $project => $version) {
      $package = $this->getPackage($project);
      if (empty($package)) {
        continue;
      }

      $path = $installationManager->getInstallPath($package);
      $this->io->write("- $project => $path", TRUE);
      $this->prepareWorkingDirectory($path, $project, $version, $options['username']);
    }
  }

  /**
   * Retrieve options from composer.json "extra" configuration.
   *
   * @return array
   *   The options.
   */
  protected function getOptions() {
    $env = new Dotenv('dorgflow', $this->io);
    $extra = $this->composer->getPackage()->getExtra() + ['dorgflow' => []];
    $options = $extra['dorgflow'] + [
      'projects' => [],
      'username' => $env->receive('drupal_org_username', 'Drupal.org username', getenv('USER')),
    ];
    return $options;
  }

  /**
   * Prepare the working directory of a git based package for dorgflow.
   *
   * @param string $path
   *   Name of the working directory.
   * @param string $project
   *   Name of the project.
   * @param string $version
   *   Version to checkout.
   * @param string $username
   *   Username on drupal.org.
   */
  protected function prepareWorkingDirectory($path, $project, $version, $username) {
    list(, $projectname) = explode('/', $project);
    $uri = $username . '@git.drupal.org:project/' . $projectname . '.git';

    // Git Clone the repository into the working directory.
    $repository = Repository::open($path);
    $repository->init();

    try {
      $origin = $repository->getRemote('origin', FALSE);
      if ($origin && $origin->getFetchURL() == $uri) {
        // Already setup correctly.
        return;
      }
    }
    catch (\Exception $ex) {
      // Ignore the exception and conitue setup.
    }

    $fs = new Filesystem();
    $fs->remove($path);
    $fs->mkdir($path);
    $repository->init();
    $repository->addRemote('origin', $uri);

    $repository->fetch();
    $repository->checkout($version);
    $repository->getCaller()->execute('branch --set-upstream-to origin/' . $version . ' ' . $version);
    $this->io->write("  - completed", TRUE);
  }

}