<?php

namespace HelpGent;

/**
 * Retrieves, sets and updates aliases for WordPress Installations.
 */
use HelpGent\Mustangostang\Spyc;
use HelpGent\WP_CLI\ExitException;
use HelpGent\WP_CLI\Utils;
/**
 * Retrieves, sets and updates aliases for WordPress Installations.
 *
 * Aliases are shorthand references to WordPress installs. For instance,
 * `@dev` could refer to a development install and `@prod` could refer to a production install.
 * This command gives you and option to add, update and delete, the registered aliases you have available.
 *
 * ## EXAMPLES
 *
 *     # List alias information.
 *     $ wp cli alias list
 *     list
 *     ---
 *     @all: Run command against every registered alias.
 *     @local:
 *       user: wpcli
 *       path: /Users/wpcli/sites/testsite
 *
 *     # Get alias information.
 *     $ wp cli alias get @dev
 *     ssh: dev@somedeve.env:12345/home/dev/
 *
 *     # Add alias.
 *     $ wp cli alias add @prod --set-ssh=login@host --set-path=/path/to/wordpress/install/ --set-user=wpcli
 *     Success: Added '@prod' alias.
 *
 *     # Update alias.
 *     $ wp cli alias update @prod --set-user=newuser --set-path=/new/path/to/wordpress/install/
 *     Success: Updated 'prod' alias.
 *
 *     # Delete alias.
 *     $ wp cli alias delete @prod
 *     Success: Deleted '@prod' alias.
 *
 * @package wp-cli
 * @when    before_wp_load
 */
class CLI_Alias_Command extends WP_CLI_Command
{
    /**
     * Lists available WP-CLI aliases.
     *
     * ## OPTIONS
     *
     * [--format=<format>]
     * : Render output in a particular format.
     * ---
     * default: yaml
     * options:
     *   - yaml
     *   - json
     *   - var_export
     * ---
     *
     * ## EXAMPLES
     *
     *     # List all available aliases.
     *     $ wp cli alias list
     *     ---
     *     @all: Run command against every registered alias.
     *     @prod:
     *       ssh: runcommand@runcommand.io~/webapps/production
     *     @dev:
     *       ssh: vagrant@192.168.50.10/srv/www/runcommand.dev
     *     @both:
     *       - @prod
     *       - @dev
     *
     * @subcommand list
     */
    public function list_($args, $assoc_args)
    {
        WP_CLI::print_value(WP_CLI::get_runner()->aliases, $assoc_args);
    }
    /**
     * Gets the value for an alias.
     *
     * ## OPTIONS
     *
     * <key>
     * : Key for the alias.
     *
     * ## EXAMPLES
     *
     *     # Get alias.
     *     $ wp cli alias get @prod
     *     ssh: dev@somedeve.env:12345/home/dev/
     */
    public function get($args, $assoc_args)
    {
        list($alias) = $args;
        $aliases = WP_CLI::get_runner()->aliases;
        if (empty($aliases[$alias])) {
            WP_CLI::error("No alias found with key '{$alias}'.");
        }
        foreach ($aliases[$alias] as $key => $value) {
            WP_CLI::log("{$key}: {$value}");
        }
    }
    /**
     * Creates an alias.
     *
     * ## OPTIONS
     *
     * <key>
     * : Key for the alias.
     *
     * [--set-user=<user>]
     * : Set user for alias.
     *
     * [--set-url=<url>]
     * : Set url for alias.
     *
     * [--set-path=<path>]
     * : Set path for alias.
     *
     * [--set-ssh=<ssh>]
     * : Set ssh for alias.
     *
     * [--set-http=<http>]
     * : Set http for alias.
     *
     * [--grouping=<grouping>]
     * : For grouping multiple aliases.
     *
     * [--config=<config>]
     * : Config file to be considered for operations.
     * ---
     * default: global
     * options:
     *   - global
     *   - project
     * ---
     *
     * ## EXAMPLES
     *
     *     # Add alias to global config.
     *     $ wp cli alias add @prod  --set-ssh=login@host --set-path=/path/to/wordpress/install/ --set-user=wpcli
     *     Success: Added '@prod' alias.
     *
     *     # Add alias to project config.
     *     $ wp cli alias add @prod --set-ssh=login@host --set-path=/path/to/wordpress/install/ --set-user=wpcli --config=project
     *     Success: Added '@prod' alias.
     *
     *     # Add group of aliases.
     *     $ wp cli alias add @multiservers --grouping=servera,serverb
     *     Success: Added '@multiservers' alias.
     */
    public function add($args, $assoc_args)
    {
        $config = !empty($assoc_args['config']) ? $assoc_args['config'] : 'global';
        list($config_path, $aliases) = $this->get_aliases_data($config, '', \true);
        $this->validate_config_file($config_path);
        $alias = $args[0];
        $grouping = Utils\get_flag_value($assoc_args, 'grouping');
        $this->validate_input($assoc_args, $grouping);
        if (isset($aliases[$alias])) {
            WP_CLI::error("Key '{$alias}' exists already.");
        }
        if (null === $grouping) {
            $aliases = $this->build_aliases($aliases, $alias, $assoc_args, \false);
        } else {
            $aliases = $this->build_aliases($aliases, $alias, $assoc_args, \true, $grouping);
        }
        $this->process_aliases($aliases, $alias, $config_path, 'Added');
    }
    /**
     * Deletes an alias.
     *
     * ## OPTIONS
     *
     * <key>
     * : Key for the alias.
     *
     * [--config=<config>]
     * : Config file to be considered for operations.
     * ---
     * options:
     *   - global
     *   - project
     * ---
     *
     * ## EXAMPLES
     *
     *     # Delete alias.
     *     $ wp cli alias delete @prod
     *     Success: Deleted '@prod' alias.
     *
     *     # Delete project alias.
     *     $ wp cli alias delete @prod --config=project
     *     Success: Deleted '@prod' alias.
     */
    public function delete($args, $assoc_args)
    {
        list($alias) = $args;
        $config = !empty($assoc_args['config']) ? $assoc_args['config'] : '';
        list($config_path, $aliases) = $this->get_aliases_data($config, $alias);
        $this->validate_config_file($config_path);
        if (empty($aliases[$alias])) {
            WP_CLI::error("No alias found with key '{$alias}'.");
        }
        unset($aliases[$alias]);
        $this->process_aliases($aliases, $alias, $config_path, 'Deleted');
    }
    /**
     * Updates an alias.
     *
     * ## OPTIONS
     *
     * <key>
     * : Key for the alias.
     *
     * [--set-user=<user>]
     * : Set user for alias.
     *
     * [--set-url=<url>]
     * : Set url for alias.
     *
     * [--set-path=<path>]
     * : Set path for alias.
     *
     * [--set-ssh=<ssh>]
     * : Set ssh for alias.
     *
     * [--set-http=<http>]
     * : Set http for alias.
     *
     * [--grouping=<grouping>]
     * : For grouping multiple aliases.
     *
     * [--config=<config>]
     * : Config file to be considered for operations.
     * ---
     * options:
     *   - global
     *   - project
     * ---
     *
     * ## EXAMPLES
     *
     *     # Update alias.
     *     $ wp cli alias update @prod --set-user=newuser --set-path=/new/path/to/wordpress/install/
     *     Success: Updated 'prod' alias.
     *
     *     # Update project alias.
     *     $ wp cli alias update @prod --set-user=newuser --set-path=/new/path/to/wordpress/install/ --config=project
     *     Success: Updated 'prod' alias.
     */
    public function update($args, $assoc_args)
    {
        $config = !empty($assoc_args['config']) ? $assoc_args['config'] : '';
        $alias = $args[0];
        $grouping = Utils\get_flag_value($assoc_args, 'grouping');
        list($config_path, $aliases) = $this->get_aliases_data($config, $alias, \true);
        $this->validate_config_file($config_path);
        $this->validate_input($assoc_args, $grouping);
        if (empty($aliases[$alias])) {
            WP_CLI::error("No alias found with key '{$alias}'.");
        }
        if (null === $grouping) {
            $aliases = $this->build_aliases($aliases, $alias, $assoc_args, \false, '', \true);
        } else {
            $aliases = $this->build_aliases($aliases, $alias, $assoc_args, \true, $grouping, \true);
        }
        $this->process_aliases($aliases, $alias, $config_path, 'Updated');
    }
    /**
     * Check whether an alias is a group.
     *
     * ## OPTIONS
     *
     * <key>
     * : Key for the alias.
     *
     * ## EXAMPLES
     *
     *     # Checks whether the alias is a group; exit status 0 if it is, otherwise 1.
     *     $ wp cli alias is-group @prod
     *     $ echo $?
     *     1
     *
     * @subcommand is-group
     */
    public function is_group($args, $assoc_args = array())
    {
        $alias = $args[0];
        $aliases = WP_CLI::get_runner()->aliases;
        if (empty($aliases[$alias])) {
            WP_CLI::error("No alias found with key '{$alias}'.");
        }
        // how do we know the alias is a group?
        // + array keys are numeric
        // + array values begin with '@'
        $first_item = $aliases[$alias];
        $first_item_key = \key($first_item);
        $first_item_value = $first_item[$first_item_key];
        if (\is_numeric($first_item_key) && \substr($first_item_value, 0, 1) === '@') {
            WP_CLI::halt(0);
        }
        WP_CLI::halt(1);
    }
    /**
     * Get config path and aliases data based on config type.
     *
     * @param string $config             Type of config to get data from.
     * @param string $alias              Alias to be used for Add/Update/Delete.
     * @param bool   $create_config_file Optional. If a config file doesn't exist,
     *                                   should it be created? Defaults to false.
     *
     * @return array Config Path and Aliases in it.
     * @throws ExitException
     */
    private function get_aliases_data($config, $alias, $create_config_file = \false)
    {
        $global_config_path = WP_CLI::get_runner()->get_global_config_path($create_config_file);
        $global_aliases = Spyc::YAMLLoad($global_config_path);
        $project_config_path = WP_CLI::get_runner()->get_project_config_path();
        $project_aliases = Spyc::YAMLLoad($project_config_path);
        if ('global' === $config) {
            $config_path = $global_config_path;
            $aliases = $global_aliases;
        } elseif ('project' === $config) {
            $config_path = $project_config_path;
            $aliases = $project_aliases;
        } else {
            $is_global_alias = \array_key_exists($alias, $global_aliases);
            $is_project_alias = \array_key_exists($alias, $project_aliases);
            if ($is_global_alias && $is_project_alias) {
                WP_CLI::error("Key '{$alias}' found in more than one path. Please pass --config param.");
            } elseif ($is_global_alias) {
                $config_path = $global_config_path;
                $aliases = $global_aliases;
            } else {
                $config_path = $project_config_path;
                $aliases = $project_aliases;
            }
        }
        return [$config_path, $aliases];
    }
    /**
     * Check if the config file exists and is writable.
     *
     * @param string $config_path Path to config file.
     *
     * @return void
     */
    private function validate_config_file($config_path)
    {
        if (!\file_exists($config_path) || !\is_writable($config_path)) {
            WP_CLI::error("Config file does not exist: {$config_path}");
        }
    }
    /**
     * Return aliases array.
     *
     * @param array  $aliases     Current aliases data.
     * @param string $alias       Name of alias.
     * @param array  $assoc_args  Associative arguments.
     * @param bool   $is_grouping Check if its a grouping operation.
     * @param string $grouping    Grouping value.
     * @param bool   $is_update   Is this an update operation?
     *
     * @return mixed
     */
    private function build_aliases($aliases, $alias, $assoc_args, $is_grouping, $grouping = '', $is_update = \false)
    {
        $alias = $this->normalize_alias($alias);
        if ($is_grouping) {
            $valid_assoc_args = ['config', 'grouping'];
            $invalid_args = \array_diff(\array_keys($assoc_args), $valid_assoc_args);
            // Check for invalid args.
            if (!empty($invalid_args)) {
                $args_info = \implode(',', $invalid_args);
                WP_CLI::error("--grouping argument works alone. Found invalid arg(s) '{$args_info}'.");
            }
        }
        if ($is_update) {
            $this->validate_alias_type($aliases, $alias, $assoc_args, $grouping);
        }
        if (!$is_grouping) {
            foreach ($assoc_args as $key => $value) {
                if (\strpos($key, 'set-') !== \false) {
                    $alias_key_info = \explode('-', $key);
                    $alias_key = empty($alias_key_info[1]) ? '' : $alias_key_info[1];
                    if (!empty($alias_key) && !empty($value)) {
                        $aliases[$alias][$alias_key] = $value;
                    }
                }
            }
        } elseif (!empty($grouping)) {
            $group_alias_list = \explode(',', $grouping);
            $group_alias = \array_map(function ($current_alias) {
                return '@' . \ltrim($current_alias, '@');
            }, $group_alias_list);
            $aliases[$alias] = $group_alias;
        }
        return $aliases;
    }
    /**
     * Validate input of passed arguments.
     *
     * @param array  $assoc_args Arguments array.
     * @param string $grouping   Grouping argument value.
     *
     * @throws ExitException
     */
    private function validate_input($assoc_args, $grouping)
    {
        // Check if valid arguments were passed.
        $arg_match = \preg_grep('/^set-(\\w+)/i', \array_keys($assoc_args));
        // Verify passed-arguments.
        if (empty($grouping) && empty($arg_match)) {
            WP_CLI::error('No valid arguments passed.');
        }
        // Check whether passed arguments contain value or not.
        $assoc_arg_values = \array_filter(\array_intersect_key($assoc_args, \array_flip($arg_match)));
        if (empty($grouping) && empty($assoc_arg_values)) {
            WP_CLI::error('No value passed to arguments.');
        }
    }
    /**
     * Validate alias type before update.
     *
     * @param array  $aliases    Existing aliases data.
     * @param string $alias      Alias Name.
     * @param array  $assoc_args Arguments array.
     * @param string $grouping   Grouping argument value.
     *
     * @throws ExitException
     */
    private function validate_alias_type($aliases, $alias, $assoc_args, $grouping)
    {
        $alias_data = $aliases[$alias];
        $group_aliases_match = \preg_grep('/^@(\\w+)/i', $alias_data);
        $arg_match = \preg_grep('/^set-(\\w+)/i', \array_keys($assoc_args));
        if (!empty($group_aliases_match) && !empty($arg_match)) {
            WP_CLI::error('Trying to update group alias with invalid arguments.');
        } elseif (empty($group_aliases_match) && !empty($grouping)) {
            WP_CLI::error('Trying to update simple alias with invalid --grouping argument.');
        }
    }
    /**
     * Save aliases data to config file.
     *
     * @param array  $aliases     Current aliases data.
     * @param string $alias       Name of alias.
     * @param string $config_path Path to config file.
     * @param string $operation   Current operation string fro message.
     */
    private function process_aliases($aliases, $alias, $config_path, $operation = '')
    {
        $alias = $this->normalize_alias($alias);
        // Convert data to YAML string.
        $yaml_data = Spyc::YAMLDump($aliases);
        // Add data in config file.
        if (\file_put_contents($config_path, $yaml_data)) {
            WP_CLI::success("{$operation} '{$alias}' alias.");
        }
    }
    /**
     * Normalize the alias to an expected format.
     *
     * - Add @ if not present.
     *
     * @param string $alias Name of alias.
     */
    private function normalize_alias($alias)
    {
        // Check if the alias starts with the @.
        // See: https://github.com/wp-cli/wp-cli/issues/5391
        if (\strpos($alias, '@') !== 0) {
            $alias = '@' . \ltrim($alias, '@');
        }
        return $alias;
    }
}
/**
 * Retrieves, sets and updates aliases for WordPress Installations.
 *
 * Aliases are shorthand references to WordPress installs. For instance,
 * `@dev` could refer to a development install and `@prod` could refer to a production install.
 * This command gives you and option to add, update and delete, the registered aliases you have available.
 *
 * ## EXAMPLES
 *
 *     # List alias information.
 *     $ wp cli alias list
 *     list
 *     ---
 *     @all: Run command against every registered alias.
 *     @local:
 *       user: wpcli
 *       path: /Users/wpcli/sites/testsite
 *
 *     # Get alias information.
 *     $ wp cli alias get @dev
 *     ssh: dev@somedeve.env:12345/home/dev/
 *
 *     # Add alias.
 *     $ wp cli alias add @prod --set-ssh=login@host --set-path=/path/to/wordpress/install/ --set-user=wpcli
 *     Success: Added '@prod' alias.
 *
 *     # Update alias.
 *     $ wp cli alias update @prod --set-user=newuser --set-path=/new/path/to/wordpress/install/
 *     Success: Updated 'prod' alias.
 *
 *     # Delete alias.
 *     $ wp cli alias delete @prod
 *     Success: Deleted '@prod' alias.
 *
 * @package wp-cli
 * @when    before_wp_load
 */
\class_alias('HelpGent\\CLI_Alias_Command', 'CLI_Alias_Command', \false);
