<?php

/**
 * @file
 * Contains \Drupal\oauth_server_sso\Form\MiniorangeConfigOAuthClient.
 */

namespace Drupal\oauth_server_sso\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\oauth_server_sso\handler;
use Drupal\oauth_server_sso\MiniorangeOAuthServerConstants;
use Drupal\oauth_server_sso\Utilities;
use Drupal\Core\Url;
use Drupal\Core\Render\Markup;
use Symfony\Component\HttpFoundation\RedirectResponse;

class MiniorangeConfigOAuthClient extends FormBase {

    public function getFormId() {
        return 'oauth_server_sso_config_client';
    }

    public function buildForm(array $form, FormStateInterface $form_state){
        $form['markup_library'] = array(
            '#attached' => array(
                'library' => array(
                    "oauth_server_sso/oauth_server_sso.style_settings",
                    'oauth_server_sso/oauth_server_sso.moCopy',
                    "core/drupal.dialog.ajax",
                )
            ),
        );

        global $base_url;
        $config = \Drupal::config('oauth_server_sso.settings');

        $attributes_arr =  array('style' => 'width:73%;');
        $configFactory = \Drupal::configFactory()->getEditable('oauth_server_sso.settings');
        $form['mo_oauth_server_style'] = array('#markup' => '<div class="mo_oauth_table_layout mo_oauth_container_full">');
        $action = isset($_GET['action']) ? $_GET['action'] : '';
        if($action == 'update'){
            $configFactory->set('oauth_server_sso_add_client_status', 'configure_client_app')->save();
        }else if($action == 'delete'){
            $configFactory->set('oauth_server_sso_add_client_status', 'delete_client_app')->save();
        }

        $status = $config->get('oauth_server_sso_add_client_status');

        if($status == 'add_client') {

            $form['markup_top_oauth_client_add_application'] = [
              '#type' => 'container',
              '#attributes' => [
                'class' => ['mo-flex-header'],
              ],
            ];
            $form['markup_top_oauth_client_add_application']['heading'] = [
              '#markup' => '<h2 class="form-heading">'.t('Configure Applications').'</h2>',
            ];

            $client_app = $config->get('oauth_server_sso_client_name');

            if(!empty($client_app)){
                $form['#attached']['library'][] = 'core/drupal.dialog.ajax';

                $form['add_new_client_app'] = array(
                    '#markup' => '<a data-dialog-type="modal" id = "oauth_server_add_new_client" href="addnewclient" class="use-ajax button button--primary ">'.t('+ Add Client').'</a>'
                );
            }else{
                $form['add_new_client_app'] = array(
                    '#type' => 'submit',
                    '#button_type' => 'primary',
                    '#value' => t('+ Add Client'),
                    '#id' => 'oauth_server_add_new_client',
                    '#submit' => ['::miniorangeOauthServerAddNewClientApp']
                );
            }

            $form['oauth_server_api_doc'] = array(
                '#markup' => '<a target="_blank" href="https://www.drupal.org/docs/contributed-modules/oauth-server-sso-setup-guides/oauth-server-api-documentation" id="oauth_server_api_doc_add_client" class="button">'.t('API Documentation').'</a>'
            );

            $header = array(
                'idp_name' => array(
                  'data' => t('Application Name')
                ),
                'client_id' => array(
                  'data' => t('Client ID')
                ),
                'client_secret' => array(
                    'data' => t('Client Secret')
                ),
                'action' => array(
                  'data' => t('Action')
                ),
                'mapping' => array(
                  'data' => t('Server Response')
                )
            );

            if(!empty($client_app)){
                $drop_button = array(
                    '#type' => 'dropbutton',
                    '#dropbutton_type' => 'small',
                    '#links' => [
                      'edit' => [
                        'title' => $this->t('Edit'),
                        'url' => Url::fromUri($base_url . '/admin/config/people/oauth_server_sso/config_client?action=update&app=' . $client_app),
                      ],
                      'delete' => [
                        'title' => $this->t('Delete'),
                        'url' => Url::fromUri($base_url . '/admin/config/people/oauth_server_sso/config_client?action=delete&app=' . $client_app),
                      ],
                    ],
                );

                $client_id = $config->get('oauth_server_sso_client_id');
                $display_id = strlen($client_id) > 25 ? substr($client_id,0,24).'...' : $client_id;
                $display_id = $client_id;
                $client_secret = $config->get('oauth_server_sso_client_secret');
                $hidden_secret = str_repeat('&bull;', strlen($client_secret));

                $table_content['oauth_server_client_apps'] = array(
                    'idp_name' => $client_app,
                    'client_id' => Markup::create('<span class="container-inline"><span id="copy_client_id">'.$display_id.'</span>&nbsp;&nbsp;<div class="callback_tooltip">
                    <span class="button mo_copy_url button--small" id="copy_button_id">
                      <span class="tooltiptext" id="copyTooltip">'.t('Copy to Clipboard').'</span>
                      &#128461;
                      </span>
                    </div></span>'),
                    'client_secret' => Markup::create('<span class="container-inline"><span id="copy_client_secret" attr="'.$client_secret.'" attrHide="'.$hidden_secret.'">'.$hidden_secret.'</span>&nbsp;&nbsp;<div class="callback_tooltip">
                    <span id="show_secret_button" class="button mo_copy_url button--small" id="show_secret">
                      <span class="tooltiptext" id="showsecretTooltip">'.t('Show Client Secret').'</span>
                      <span id="secret_button_text">'.t('View').'</span>
                    </span>
                    </div><div class="callback_tooltip">
                    <span class="button mo_copy_url button--small" id="copy_button_secret">
                      <span class="tooltiptext" id="secretTooltip">'.t('Copy to Clipboard').'</span>
                      &#128461;
                      </span>
                    </div></span>'),
                    'action' => array(
                      'data' => $drop_button,
                    ),
                    'mapping' => Markup::create('<a class="button button--small" href=" '.$base_url.'/admin/config/people/oauth_server_sso/server_mapping">'.t('Configure').'</a>')
                  );
            }

            $table_content = $table_content ?? [];

            $form['mo_oauth_server_client_app_list_table'] = array(
                '#type' => 'table',
                '#header' => $header,
                '#rows' => $table_content,
                '#attributes' => array(
                    'class' => array('tableborder'),),
                '#empty' => t('Please add a client application by clicking above').'<b>'.t('+ Add Client').'</b>'.t('button to generate the Client ID and Secret'),
                '#prefix' => '<br><br>',
                '#suffix' => '<br>',
            );

            self::getMoOAuthEndpointsTable($form,$form_state);
            self::getGrantTypeDescTable($form,$form_state);

        }else if($status == 'configure_client_app'){
            $form['markup_top_oauth_client_add_application'] = [
              '#type' => 'container',
              '#attributes' => [
                'class' => ['mo-flex-header'],
              ],
            ];
            if($action == 'update'){
              $form['markup_top_oauth_client_add_application']['heading'] = [
                '#markup' => '<h2 class="form-heading">'.t('Update Client').'</h2>',
              ];
            }else{
              $form['markup_top_oauth_client_add_application']['heading'] = [
                '#markup' => '<h2 class="form-heading">'.('Add Client').'</h2>',
              ];
            }

          $form['markup_top_oauth_client_add_application']['actions'] = [
            '#type' => 'container',
            '#attributes' => [
              'class' => ['mo-header-buttons'],
            ],
          ];
          $form['markup_top_oauth_client_add_application']['actions']['button1'] = [
            '#type' => 'link',
            '#title' => $this->t('API Documentation'),
            '#url' => Url::fromUri('https://www.drupal.org/docs/contributed-modules/oauth-server-sso-setup-guides/oauth-server-api-documentation'),
            '#attributes' => [
              'class' => ['button', 'button--primary'],
              'target' => '_blank',
            ],
          ];

          $form['markup_top_oauth_client_add_application']['actions']['button2'] = [
            '#type' => 'link',
            '#title' => $this->t('Setup Guides'),
            '#url' => Url::fromUri('https://plugins.miniorange.com/drupal-oauth-server-guides'),
            '#attributes' => [
              'class' => ['button', 'button--primary'],
              'target' => '_blank',
            ],
          ];

            $form['miniorange_oauth_client_name'] = array(
                '#type' => 'textfield',
                '#default_value' => $config->get('oauth_server_sso_client_name'),
                '#title' => t('Application Name'),
                '#required' => true,
                '#maxlength' => 1048,
                '#attributes' => $attributes_arr,
            );

            $form['miniorange_oauth_server_callback_url'] = array(
                '#type' => 'url',
                '#default_value' => $config->get('oauth_server_sso_redirect_url'),
                '#title' => t('Callback/Redirect URL'),
                '#required' => true,
                '#maxlength' => 1048,
                '#attributes' => ['style' => 'width:73%;','class' => ['container-inline']],
            );

            $form['#attached']['library'][] = 'core/drupal.dialog.ajax';

            $form['miniorange_oauth_server_buttons_container'] = [
                '#type' => 'container',
                '#attributes' => ['style' => 'display: flex; align-items: center; gap: 10px;'],
            ];
            $form['miniorange_oauth_server_buttons_container']['miniorange_oauth_server_save_client'] = array(
                '#type' => 'submit',
                '#value' => t('Save'),
                '#button_type' => 'primary',
                '#submit' => array('::oauth_server_sso_next_1'),
            );
            $form['miniorange_oauth_server_buttons_container']['miniorange_oauth_server_add_more'] = [
                '#markup' => '<a data-dialog-type="modal" href="addnewcallbackurls" class="use-ajax button">'.t('+ Add More').'</a>',
            ];

            self::getMoOAuthEndpointsTable($form,$form_state);
            self::getGrantTypeDescTable($form,$form_state);

        }else if($status == 'delete_client_app'){
            $configFactory->clear('oauth_server_sso_client_name')
            ->clear('oauth_server_sso_client_id')
            ->clear('oauth_server_sso_client_secret')
            ->clear('oauth_server_sso_redirect_url')
            ->set('oauth_server_sso_add_client_status', 'configure_client_app')
            ->save();
            \Drupal::messenger()->addStatus($this->t('Configurations deleted successfully.'));

            $response = new RedirectResponse($base_url.'/admin/config/people/oauth_server_sso/config_client');
            $response->send();
            exit;
        }
        Utilities::moOAuthServerShowCustomerSupportIcon($form, $form_state);
        return $form;
    }

    public function miniorange_oauth_server_endpoints($endpoint_name, $endpoint_value, $grant = ''){
        $row[$endpoint_name] = [
            '#markup' => '<div class="container-inline"><strong>'. t($endpoint_name) . '</strong>',
        ];

        if($endpoint_name == 'Authorization Code Grant'){
            $auth_code_table_key = str_replace(' ', '_', $endpoint_name);
            $row[$auth_code_table_key] = [
                '#markup' => '<span id="copy_'.str_replace(' ', '_', $endpoint_name).'">'.t($endpoint_value).'</span>',
            ];
        }else if($endpoint_name == 'Scope'){
            $row[$endpoint_value] = [
                '#markup' => '<span id="copy_'.str_replace(' ', '_', $endpoint_name).'">'.t($endpoint_value).'</span>&nbsp;&nbsp;&nbsp;<span><a data-dialog-type="modal" data-dialog-options="{&quot;width&quot;:&quot;70%&quot;}" id = "miniorange_oauth_server_scope_based_response" href="scopebasedresponse" class="use-ajax">Know More</a></span>',
            ];
        }else{
            $row[$endpoint_value] = [
                '#markup' => '<span id="copy_'.str_replace(' ', '_', $endpoint_name).'">'.t($endpoint_value).'</span>',
            ];
        }

        if(empty($grant)){
            $row['copy_'.$endpoint_name] = array(
                '#value' => t('&#128461;'),
                '#type' => 'button',
                '#id' => 'copy_button_'.str_replace(' ', '_', $endpoint_name),
                '#attributes' => ['onclick' => 'CopyToClipboard(copy_'.str_replace(' ', '_', $endpoint_name).')', 'class' => ['use-ajax','button--small']],
                '#ajax' => ['event' => 'click',
                           'progress' => false
                ],
                '#suffix' => '</div>',
            );
        }

        return $row;
    }

    public function getMoOAuthEndpointsTable(array &$form, FormStateInterface $form_state){
        global $base_url;
        $config = \Drupal::config('oauth_server_sso.settings');

        $module_path = \Drupal::service('extension.list.module')->getPath("oauth_server_sso");
        $form['markup_top_oauth_server_endpoints'] = array(
            '#type' => 'fieldset',
        );

        $client_id = $config->get('oauth_server_sso_client_id');
        $client_secret = $config->get('oauth_server_sso_client_secret');

        if($client_id && $client_secret){
          $form['markup_top_oauth_server_endpoints']['mo_oauth_server_attrs_list_idp'] = array(
            '#type' => 'table',
            '#attributes' => ['style' => 'border-collapse: separate;'],
            '#caption' => $this->t('
            <div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap;">
             <div style="font-size: 1.25rem; font-weight: 600;">' . t('Scope & Endpoints') . '</div>
              <div style="display: flex; align-items: center; gap:-2px;">
              <div class="callback_tooltip mo_postman_collection_tooltip" style="display: flex; align-items: center;">
               <span class="mo_postman_collection">
                <span class="tooltiptext" style="width: 230px; margin-left: -115px;" id="myTooltip">' . t('This will help you to test the OAuth Server with Postman as Client') . '</span>
                 <a href="postman-collection" class="button button--small" style="display: flex; align-items: center;">
                 <img src="' . $base_url . '/' . $module_path . '/includes/images/download.svg" width="18" style="margin-right: 4px;" />
                  ' . t('Download Postman Collection') . '
                 </a>
                </span>
              </div>
            <div class="callback_tooltip mo_test_postman_collection" style="display: flex; align-items: center;">
              <span>
               <span class="tooltiptext" style="width: 150px; margin-left: -80px;" id="myTooltip">' . t('Guide to test OAuth Server with Postman as client') . '</span>
                <a href="https://www.drupal.org/docs/contributed-modules/oauth-server-sso-setup-guides/postman-as-oauth-client" target="_blank">
                 <img src="' . $base_url . '/' . $module_path . '/includes/images/questionmark.svg" width="18" />
                </a>
              </span>
            </div>
            </div>
            </div><hr>'),
            '#header' => [t('Name'), t('Value'), ''],
            '#empty' => t('Something is not right. Please run the update script or contact us at <a href="mailto:' . MiniorangeOAuthServerConstants::SUPPORT_EMAIL . '">' . MiniorangeOAuthServerConstants::SUPPORT_EMAIL . '</a>'),
            '#responsive' => TRUE,
          );

        }else{
            $form['markup_top_oauth_server_endpoints']['mo_oauth_server_attrs_list_idp'] = array(
                '#type' => 'table',
                '#attributes' => ['style' => 'border-collapse: separate;'],
                '#caption' => $this->t('<span><h4>'.t('Scope & Endpoints').'</h4></span>'),
                '#header' => [t('Name'),t('Value'),''],
                '#empty' => t('Something is not right. Please run the update script or contact us at <a href="mailto:'.MiniorangeOAuthServerConstants::SUPPORT_EMAIL.'">'. MiniorangeOAuthServerConstants::SUPPORT_EMAIL .'</a>'),
                '#responsive' => TRUE ,
            );
        }

        $data = [
            'Scope' => 'profile openid email',
            'Authorize Endpoint' => $base_url.'/mo/oauth2/authorize',
            'Access Token Endpoint' => $base_url.'/mo/oauth2/token',
            'Get User Info Endpoint' => $base_url.'/mo/oauth2/userinfo',
            'Discovery Endpoint' => $base_url.'/mo/well-known/openid-configuration'
        ];

        $form['#attached']['library'][] = 'core/drupal.dialog.ajax';

        foreach ($data as $key => $value) {
            $row = self::miniorange_oauth_server_endpoints($key, $value);
            $form['markup_top_oauth_server_endpoints']['mo_oauth_server_attrs_list_idp'][$key] = $row;
        }
    }

    public function getGrantTypeDescTable(array &$form, FormStateInterface $form_state){
        global $base_url;
        $url_path = $base_url . '/' . \Drupal::service('extension.list.module')->getPath('oauth_server_sso'). '/includes/images';

        $form['markup_top_oauth_server_grant_type_desc'] = array(
            '#type' => 'fieldset',
        );

        $form['markup_top_oauth_server_grant_type_desc']['mo_oauth_server_grant_type_table'] = array(
            '#type' => 'table',
            '#header' => [t('Grant Type'),t('Description')],
            '#tableselect' => true,
            '#js_select' => false,
            '#disabled' => true,
            '#caption' => $this->t('<span><h5>'.t('Grant Type').'&nbsp;<a href="licensing"><img class="mo_oauth_pro_icon1" src="' . $url_path . '/pro.png" alt="Premium"><span class="mo_pro_tooltip">'.t('Available in the Premium version').'</span></a><hr></h5></span>'),
            '#default_value' => ['Authorization Code Grant' => true],
            '#empty' => t('Something is not right. Please run the update script or contact us at ').'<a href="mailto:'.MiniorangeOAuthServerConstants::SUPPORT_EMAIL.'">'. MiniorangeOAuthServerConstants::SUPPORT_EMAIL .'</a>',
            '#responsive' => TRUE ,
            '#attributes' => ['style' => 'border-collapse: separate;'],
        );

        $data = [
            'Authorization Code Grant' =>	'The Authorization Code Grant flow is used to obtain an access token by exchanging authorization code with OAuth server.',
            'Password Grant' => 'This Grant is used to obtain access token by exchanging user\'s username and password in the Token Endpoint.',
            'Implicit Grant' => 'In this Grant The OAuth server issues access tokens directly after validating the user\'s credentials in the Authorize Endpoint.',
            'Client Credentials Grant' => 'This Grant allows the Clients to obtain an access token without user authentication by providing only its Client ID and Client Secret.',
            'Refresh Token Grant' => 'The Refresh Token grant is used to obtain a new access token after the current one has expired by exchanging a Refresh Token.'
        ];

        foreach ($data as $key => $value) {
            $row = self::miniorange_oauth_server_endpoints($key, $value, $grant = 'scope');
            $form['markup_top_oauth_server_grant_type_desc']['mo_oauth_server_grant_type_table'][$key] = $row;
        }

    }

    public function miniorangeOauthServerAddNewClientApp(){
        $configFactory = \Drupal::configFactory()->getEditable('oauth_server_sso.settings');
        $configFactory->set('oauth_server_sso_add_client_status', 'configure_client_app')->save();
    }

    public function miniorange_oauth_server_configuration($attr_name, $attr_value, $attributes_arr){
        $config = \Drupal::config('oauth_server_sso.settings');
        $row[$attr_name] = [
            '#markup' => '<div class="container-inline"><strong>'. $attr_name . '</strong>',
        ];

        if($attr_name == 'Client ID' || $attr_name == 'Client Secret'){
            $row[$attr_value] = [
                '#markup' => '<span id="copy_'.str_replace(' ', '_', $attr_name).'">'.$attr_value.'</span>',
            ];

            $row['copy_'.$attr_name] = array(
                '#value' => t('&#128461; Copy'),
                '#type' => 'button',
                '#id' => 'copy_button_'.str_replace(' ', '_', $attr_value),
                '#attributes' => ['onclick' => 'CopyToClipboard(copy_'.str_replace(' ', '_', $attr_name).')', 'class' => ['use-ajax']],
                '#ajax' => ['event' => 'click',
                    'progress' => [
                        'type' => 'throbber',
                        'message' => $this->t('Copying'),
                    ]
                ],
                '#suffix' => '</div>',
            );
        }elseif ($attr_value == 'oauth_server_sso_client_name'){
            $row[$attr_value] = [
                '#type' => 'textfield',
                '#required' => true,
                '#default_value' => $config->get($attr_value),
                '#disabled' => TRUE,
                '#attributes' => $attributes_arr,
                '#suffix' => '</div>'
            ];
        }else{
            $row[$attr_value] = [
                '#type' => 'textfield',
                '#required' => true,
                '#attributes' => $attributes_arr,
                '#default_value' => $config->get($attr_value),
                '#suffix' => '</div>'
            ];
        }
        return $row;
    }

    function oauth_server_sso_next_1(array &$form, FormStateInterface $form_state){
        $form_values = $form_state->getValues();
        $configFactory = \Drupal::configFactory()->getEditable('oauth_server_sso.settings');
        $client_name = $form_values['miniorange_oauth_client_name'];
        $redirect_url = $form_values['miniorange_oauth_server_callback_url'];

        $configFactory->set('oauth_server_sso_client_name',$client_name)->save();
        $configFactory->set('oauth_server_sso_redirect_url',$redirect_url)->save();

        $action = isset($_GET['action'])?$_GET['action']:'';
        if($action != 'update'){
            $client_id = handler::generateRandom(20);
            $client_secret = handler::generateRandom(40);
            $configFactory = \Drupal::configFactory()->getEditable('oauth_server_sso.settings');
            $configFactory->set('oauth_server_sso_client_id', $client_id)->save();
            $configFactory->set('oauth_server_sso_client_secret', $client_secret)->save();
        }
        $configFactory->set('oauth_server_sso_add_client_status', 'add_client')->save();
        \Drupal::messenger()->addStatus($this->t('Configurations saved successfully.'));
        $form_state->setRedirectUrl(Url::fromRoute('oauth_server_sso.config_client'));
    }

    function oauth_server_sso_next_2(array &$form, FormStateInterface $form_state){
        $form_values = $form_state->getValues();
        $callback_url = $form_values['mo_oauth_server_configuration_table']['Redirect/Callback URL']['oauth_server_sso_redirect_url'];

        $config = \Drupal::configFactory()->getEditable('oauth_server_sso.settings');
        $config->set('oauth_server_sso_redirect_url', $callback_url)
               ->set('oauth_server_sso_add_client_status', 'add_client')
               ->save();
        \Drupal::messenger()->addMessage($this->t('Configurations saved successfully.'));
        $form_state->setRedirectUrl(Url::fromRoute('oauth_server_sso.config_client'));

    }

    function oauth_server_sso_delete_client(array &$form, FormStateInterface $form_state){
       $config = \Drupal::configFactory()->getEditable('oauth_server_sso.settings');
       $config->clear('oauth_server_sso_client_name')
               ->clear('oauth_server_sso_client_id')
               ->clear('oauth_server_sso_client_secret')
               ->clear('oauth_server_sso_redirect_url')
               ->clear('oauth_server_sso_add_client_status')
               ->save();
    }

    function submitForm(array &$form, FormStateInterface $form_state){

    }

}