<?php

namespace LakeDrops\DorgFlow;

use Composer\Package\PackageInterface;
use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\Script\Event as ScriptEvent;
use GitElephant\Repository;
use LakeDrops\Component\Dotenv\Dotenv;
use Symfony\Component\Filesystem\Filesystem;

class Handler {

  /**
   * @var \Composer\Composer
   */
  protected $composer;

  /**
   * @var \Composer\IO\IOInterface
   */
  protected $io;

  /**
   * Handler constructor.
   *
   * @param Composer $composer
   * @param IOInterface $io
   */
  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 PackageInterface
   */
  protected function getPackage($name) {
    return $this->composer->getRepositoryManager()->getLocalRepository()->findPackage($name, '*');
  }

  /**
   * Post install/update event to prepare projects for development.
   *
   * @param ScriptEvent $event
   */
  public function prepareDevProjects($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 excludes from optional "extra" configuration.
   *
   * @return array
   */
  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;
  }

  /**
   * @inheritDoc
   */
  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);
  }

}