#!/usr/bin/env php
<?php

/*
 * Run this script to automatically update the Configuration section
 * of the README.md file.
 */

require __DIR__.'/../vendor/autoload.php';

use KnpU\OAuth2ClientBundle\DependencyInjection\KnpUOAuth2ClientExtension;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ArrayNode;
use Symfony\Component\Config\Definition\BooleanNode;
use Symfony\Component\Config\Definition\NodeInterface;

function replaceInString($startTextMarker, $endTextMarker, $fullText, $replacementText)
{
    $startPos = strpos($fullText, $startTextMarker);
    $endPos = strpos($fullText, $endTextMarker);

    if ($startPos === false || $endPos === false) {
        throw new \Exception('Could not find start or end text! '.$startTextMarker.' '.$endTextMarker);
    }

    $originalContents = $fullText;
    $newContents = substr($originalContents, 0, $startPos);
    $newContents .= $replacementText;
    $newContents .= substr($originalContents, $endPos+strlen($endTextMarker));

    return $newContents;
}

$sectionTemplate = <<<EOF
        # will create service: "knpu.oauth2.client.%PROVIDER_NAME%"
        # an instance of: %CLIENT_CLASS%
        # composer require %PACKAGE_NAME%
        %PROVIDER_NAME%:
            # must be "%PROVIDER_NAME%" - it activates that type!
            type: %PROVIDER_NAME%
            # add and set these environment variables in your .env files
            client_id: '%env(OAUTH_%UCPROVIDER_NAME%_CLIENT_ID)%'
            %CLIENT_SECRET%
            # a route name you'll create
            redirect_route: connect_%PROVIDER_NAME%_check
            redirect_params: {}
            %ADDITIONAL_CONFIG%
            # whether to check OAuth2 "state": defaults to true
            # use_state: true
EOF;

$extension = new KnpUOAuth2ClientExtension();
$configSections = [];
$installTreeDetails = [
    'longest_name_and_url' => 0,
    'longest_package_name' => 0,
    'longest_name_and_url_link' => 0,
    'longest_install_command' => 0,
    'types' => []
];
foreach (KnpUOAuth2ClientExtension::getAllSupportedTypes() as $type) {
    // we don't document the "generic" type in this way
    if ($type == 'generic') {
        continue;
    }

    $tree = new TreeBuilder('knpu_oauth2_client');
    $configNode = method_exists($tree, 'getRootNode')
        ? $tree->getRootNode()
        : $tree->root('knpu_oauth2_client');
    $configurator = $extension->getConfigurator($type);
    $configurator->buildConfiguration($configNode->children());

    /** @var ArrayNode $arrayNode */
    $arrayNode = $tree->buildTree();
    $customKeys = array();

    $installTreeDetails['types'][$type] = [
        'package' => $configurator->getPackagistName(),
        'provider_name' => $configurator->getProviderDisplayName(),
        'homepage' => $configurator->getLibraryHomepage(),
    ];
    if (strlen($configurator->getPackagistName()) > $installTreeDetails['longest_package_name']) {
        $installTreeDetails['longest_package_name'] = strlen($configurator->getPackagistName());
        $installTreeDetails['longest_install_command'] = $installTreeDetails['longest_package_name'] + 17; // where 17 is the length of Composer command, i.e. "composer require "
    }

    $nameAndUrlLength = strlen($configurator->getProviderDisplayName().$configurator->getLibraryHomepage());
    if ($nameAndUrlLength > $installTreeDetails['longest_name_and_url']) {
        $installTreeDetails['longest_name_and_url'] = $nameAndUrlLength;
        $installTreeDetails['longest_name_and_url_link'] = $nameAndUrlLength + 4; // where 4 is the length of Markdown link syntax, i.e. "[]()"
    }

    foreach ($arrayNode->getChildren() as $child) {
        /** @var NodeInterface $child */

        if ($child instanceof ArrayNode) {
            $defaultValue = $child->getDefaultValue()
                // *should* ? come out looking like valid-ish YAML
                ? json_encode($child->getDefaultValue())
                : '{}';

        } elseif ($child instanceof BooleanNode) {
            $defaultValue = $child->getDefaultValue()
                ? 'true'
                : 'false';
        } else {
            if ($child->getDefaultValue()) {
                $defaultValue = $child->getDefaultValue();
            } else {
                if ('string' === gettype($child->getDefaultValue())) {
                    $defaultValue = "''";
                } else {
                    $defaultValue = 'null';
                }
            }
        }

        if ($child->getInfo()) {
            $customKeys[] = '# '.$child->getInfo();
        }

        // if not required, comment out: it's extra
        $keyPrefix = $child->isRequired() ? '' : '# ';
        $example = $child->getExample() ? $child->getExample() : sprintf('%s: %s', $child->getName(), $defaultValue);
        $customKeys[] = $keyPrefix . $example;
    }

    $newSection = $sectionTemplate;

    if (KnpUOAuth2ClientExtension::configuratorNeedsClientSecret($configurator)) {
        $newSection = str_replace(
            '%CLIENT_SECRET%',
            "client_secret: '%env(OAUTH_%UCPROVIDER_NAME%_CLIENT_SECRET)%'",
            $newSection
        );
    } else {
        $newSection = str_replace(
            '            %CLIENT_SECRET%'.PHP_EOL,
            '',
            $newSection
        );
    }

    $newSection = str_replace('%UCPROVIDER_NAME%', strtoupper($type), $newSection);
    $newSection = str_replace('%PROVIDER_NAME%', $type, $newSection);
    $newSection = str_replace('%CLIENT_CLASS%', $configurator->getClientClass(array()), $newSection);
    $newSection = str_replace('%PACKAGE_NAME%', $configurator->getPackagistName(), $newSection);

    if (empty($customKeys)) {
        $newSection = str_replace(
            '            %ADDITIONAL_CONFIG%'.PHP_EOL,
            '',
            $newSection
        );
    } else {
        $newSection = str_replace(
            '%ADDITIONAL_CONFIG%',
            implode("\n            ", $customKeys),
            $newSection
        );
    }

    $configSections[] = $newSection;
}

$readmeContents = file_get_contents(__DIR__.'/../README.md');

/*
 * START UPDATE INSTALL TREE
 */

$installTemplateText = <<<EOF
<a name="client-downloader-table"></a>

%INSTALL_TABLE%

<span name="end-client-downloader-table"></span>
EOF;


$longestNameAndUrl = $installTreeDetails['longest_name_and_url'];
$longestPackageName = $installTreeDetails['longest_package_name'];
$longestNameAndUrlLink = $installTreeDetails['longest_name_and_url_link'];
$longestInstallCommand = $installTreeDetails['longest_install_command'];

// setup the header line
$columnHeader1 = 'OAuth2 Provider';
$columnHeader2 = 'How to Install';

$installTable = '| '.$columnHeader1;
$installTable .= str_repeat(' ', $longestNameAndUrlLink - strlen($columnHeader1));
$installTable .= ' | '.$columnHeader2;
$installTable .= str_repeat(' ', $longestInstallCommand - strlen($columnHeader2));
$installTable .= ' |';
// adding the next line, with | ---- | ---- |
$installTable .= "\n";
$installTable .= '| '.str_repeat('-', $longestNameAndUrlLink).' | ';
$installTable .= str_repeat('-', $longestInstallCommand).' |';

$lines = [];
foreach ($installTreeDetails['types'] as $typeConfig) {
    $line = sprintf(
        '| [%s](%s) _SPACES1_| composer require %s _SPACES2_|',
        $typeConfig['provider_name'],
        $typeConfig['homepage'],
        $typeConfig['package']
    );

    $spaces1 = $longestNameAndUrl - strlen($typeConfig['provider_name'].$typeConfig['homepage']);
    $spaces2 = $longestPackageName - strlen($typeConfig['package']);

    $line = str_replace('_SPACES1_', str_repeat(' ', $spaces1), $line);
    $line = str_replace('_SPACES2_', str_repeat(' ', $spaces2), $line);

    $lines[] = $line;
}

// add generic
$genericProviderLink = '[Generic](#configuring-a-generic-provider)';
$genericProviderDescription = 'configure any unsupported provider';
$lines[] = sprintf(
    '| %s %s| %s %s|',
    $genericProviderLink,
    str_repeat(' ', $longestNameAndUrlLink - strlen($genericProviderLink)),
    $genericProviderDescription,
    str_repeat(' ', $longestInstallCommand - strlen($genericProviderDescription))
);

$installTable .= "\n".implode("\n", $lines);
$finalInstallText = str_replace(
    '%INSTALL_TABLE%',
    $installTable,
    $installTemplateText
);

$readmeContents = replaceInString(
    '<a name="client-downloader-table"></a>',
    '<span name="end-client-downloader-table"></span>',
    $readmeContents,
    $finalInstallText
);



/*
 * START UPDATE CONFIGURATION
 */
$configurationText = <<<EOF
## Configuration

Below is the configuration for *all* of the supported OAuth2 providers.
**Don't see the one you need?** Use the `generic` provider to configure
any provider:

```yml
# config/packages/knpu_oauth2_client.yaml
knpu_oauth2_client:
    # can be set to the service id of a service that implements Guzzle\ClientInterface
    # http_client: null

    # options to configure the default http client
    # http_client_options:
    #     timeout: 0
    #     # if you want to disable the proxy (e.g. local GitLab OAuth) - set it to "false"
    #     proxy: null
    #     Use only with proxy option set
    #     verify: false

    clients:
%PROVIDERS_ENTRIES%
```

## Configuring a Generic Provider
EOF;

$finalConfigurationText = str_replace(
    '%PROVIDERS_ENTRIES%',
    implode("\n\n", $configSections),
    $configurationText
);

$readmeContents = replaceInString(
    '## Configuration',
    '## Configuring a Generic Provider',
    $readmeContents,
    $finalConfigurationText
);

/*
 * END UPDATE CONFIGURATION
 */

file_put_contents(__DIR__.'/../README.md', $readmeContents);
echo "\n\n    README.md Updated!\n\n";
