<?php

namespace Velis\VersionControl\Git;

use Exception;
use Velis\App;

/**
 * Git shell adapter
 * @author Bartosz Izdebski <bartosz.izdebski@velis.pl>
 */
class Shell implements Adapter
{
    /**
     * Repository URL
     * @var Repository
     */
    protected $_repository;


    protected $_connection;


    /**
     * Constructor
     * @param string $repository
     * @throws Exception
     */
    public function __construct($repository)
    {
        $this->_repository = $repository;

        list($username, $repositoryData) = explode('@', $this->_repository->url);
        $host = current(explode(':', $repositoryData));

        $connection = ssh2_connect($host);
        ssh2_auth_pubkey_file($connection, $username, App::$config->git->publicKeyPath, App::$config->git->privateKeyPath);

        if (!$connection) {
            throw new Exception('No connection to git repository server');
        }

        $this->_connection = $connection;
    }


    public function execRemoteCommand($command)
    {
        $output = array();

        $stream = ssh2_exec($this->_connection, $command);
        stream_set_blocking($stream, true);

        while ($line = fgets($stream)) {
            $output[] = $line;
        }

        return $output;
    }

    /**
     * Return latest rev hash
     * @return string
     */
    public function getHeadRevision()
    {
        $command = 'cd ' . $this->_repository->repoDirectory();
        $command .= ' && git --no-pager log --all -n 1 --pretty=oneline --no-abbrev-commit';

        $output = $this->execRemoteCommand($command);

        return substr($output[0], 0, 40);
    }


    /**
     * Info about revisions
     * @param string $revision
     * @param null $limit
     * @param string|null $revisionHash
     * @return array
     */
    public function getInfo($revision, $limit = null, $revisionHash = null)
    {
        $command = 'cd ' . $this->_repository->repoDirectory();
        if ($revisionHash) {
            $command .= '&& git show --name-only ' . $revisionHash;
        } else {
            $command .= ' && git --no-pager log --all --no-abbrev-commit --format=medium';
            if ($revision) {
                $command .= ' --since="10 day"';
            }
        }

        $branchInfo = 'cd ' . $this->_repository->repoDirectory() . ' && git branch --contains ';

        $output = $this->execRemoteCommand($command);

        $info = array();
        $infoRev = array();
        foreach ($output as $line) {
            if (substr($line, 0, 6) == 'commit') {
                if ($infoRev) {
                    $infoRev['message'] = trim($infoRev['message']);
                    $info[$infoRev['rev']] = $infoRev;
                }

                $infoRev = [
                    'rev' => trim(str_replace('commit', '', $line)),
                    'message' => '',
                ];
                $branches = $this->execRemoteCommand($branchInfo . $infoRev['rev']);
                $infoRev['branch'] = trim(implode(PHP_EOL, $branches), '* ');
                if ($infoRev['rev'] == $revision) {
                    return $info;
                }
            } elseif (substr($line, 0, 7) == 'Author:') {
                if (preg_match_all('/<+(.*?)>/', $line, $matches)) {
                    $infoRev['author_email'] = $matches[1][0];
                }
            } elseif (substr($line, 0, 6) == 'Merge:') {
            } elseif (substr($line, 0, 5) == 'Date:') {
                $date = trim(str_replace('Date:', '', $line));
                $infoRev['date'] = date('Y-m-d H:i:s', strtotime($date));
            } else {
                $infoRev['message'] .= "\n" . $line;
            }
        }

        if ($infoRev) {
            $infoRev['message'] = trim($infoRev['message']);
            $info[$infoRev['rev']] = $infoRev;
        }

        return $info;
    }


    /**
     * Info about changed files in revision
     * @param int $revision
     * @return array
     */
    public function getFiles($revision)
    {
//        $command = 'svn diff -c '.$revision.' --summarize '.$this->_repositoryUrl;
//        exec($command, $output);
//
//        $changelog = array();
//
//        foreach ($output as $change) {
//
//            $change = preg_replace('/[ ]+/', ';', trim($change));
//            $changeArray = explode(";", $change);
//            $changelog[] = array(
//                'operation' => $changeArray[0],
//                'file' => str_replace($this->_repositoryUrl, '', $changeArray[1])
//            );
//        }
//
//        return $changelog;
    }
}
