<?php

namespace Drupal\azure_ad\Form;

use Drupal;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Html;
use Drupal\Core\Config\Config;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\Url;
use Drupal\azure_ad\Helper\moAzureADHelper;
use Drupal\user_provisioning\moUserProvisioningConstants;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\OpenModalDialogCommand;
use Drupal\Core\Form\formBuilder;

class MoAzureOverview extends FormBase
{
    private $base_url;
    private ImmutableConfig $config;
    public Config $config_factory;
    protected $messenger;
    private string $theme_name;
    private string $url_path;

    public function __construct()
    {
        global $base_url;
        $this->base_url = $base_url;
        $this->config = Drupal::config('azure_ad.settings');
        $this->config_factory = Drupal::configFactory()->getEditable('azure_ad.settings');
        $this->messenger = Drupal::messenger();
        $this->theme_name = \Drupal::theme()->getActiveTheme()->getName();
        $this->url_path = $this->base_url . '/' . \Drupal::service('extension.list.module')->getPath('azure_ad'). '/includes';
    }

    /**
     * @inheritDoc
    */
    public function getFormId(): string
    {
        return "mo_azure_overview";
    }

    /**
     * @inheritDoc
     */
    public function buildForm(array $form, FormStateInterface $form_state)
    {
        $form['mo_azure_ad_overview_add_css'] = [
            '#attached' => [
                'library' => [
                    'azure_ad/azure_ad.admin',
                    'core/drupal.dialog.ajax',
                ]
            ],
        ];

        if(!\Drupal::service('module_handler')->moduleExists('user_provisioning')){
            \Drupal::service('module_installer')->install(['user_provisioning']);
        }

        $azure_ad_provisioning_step_no = $this->config->get('azure_ad_provisioning_step');
        
        if (empty($azure_ad_provisioning_step_no)) {
            $this->AzureAdStep0($form, $form_state);
        } else if ($azure_ad_provisioning_step_no == 'step1'){
            $this->AzureADStep1($form, $form_state);
        } else if ($azure_ad_provisioning_step_no == 'step2'){
            $this->AzureADStep2($form, $form_state);
        } else if ($azure_ad_provisioning_step_no == 'step3'){
            $this->AzureADStep3($form, $form_state);
        }else{
            $response = new RedirectResponse(Url::fromRoute('azure_ad.configure_azure')->toString());
            $response->send();
            return new Response();
        }

        $azure_ad_helper = new moAzureADHelper();
        $azure_ad_helper->moAzureShowCustomerSupportIcon($form, $form_state);

        return $form;
    }

    /**
     * @inheritDoc
     */
    public function submitForm(array &$form, FormStateInterface $form_state)
    {
        $this->config_factory->set('azure_ad_provisioning_step', 'step1')->save();
    }

    private function AzureAdStep0(array &$form, FormStateInterface $form_state){

        $form['overview_header_style'] = [
            '#markup' => t('<div class="mo_azure_header_container">'),
        ];

        $current_logged_in_user = \Drupal::currentUser()->getDisplayName();
        $current_logged_in_user = !empty($current_logged_in_user) ? $current_logged_in_user : 'there';

        $form['overview_left_side_content'] = [
            '#markup' => t('<div class="mo_azure_header_container_left">
                <h2>Let\'s Get Started!</h2>
                <p>Hello ' . $current_logged_in_user . ', thank you for installing <strong>User Sync For Azure AD/B2C</strong> module! <br><br>This module offers bidirectional user synchronization between your Azure AD/B2C and your Drupal site using Microsoft Graph APIs. Make sure to check out the list of supported features and integrations to increase the functionality of your Drupal site.
                <br><br>Feel free to contact us at <a href="mailto:'.moUserProvisioningConstants::SUPPORT_EMAIL.'">'.moUserProvisioningConstants::SUPPORT_EMAIL.'</a> for further queries or questions.</p>')
        ];

        $form['overview_left_side_guide_button'] = [
            '#type' => 'link',
            '#title' => t('&#128366; &nbsp; Setup Guide'),
            '#url' => Url::fromUri('https://www.drupal.org/docs/contributed-modules/azure-drupal-sync'),
            '#attributes' => ['class' => ['button', 'button--primary'], 'target' => '_blank'],
            '#prefix' => '<div class="container-inline">'
        ];

        $form['overview_left_side_configure_button'] = [
            '#type' => 'submit',
            '#value' => t('&#9881; &nbsp; Let\'s configure the module &nbsp; &#11166;'),
            '#button_type' => 'primary',
            '#suffix' => '</div>',
        ];

        $form['overview_left_side_content_end'] = [
            '#markup' => '</div>'
        ];

        $form['overview_right_side_content'] = [
            '#markup' => t('<div class="mo_azure_header_container_right"><a class="mo_azure_header_container_right_video" href="https://www.youtube.com/watch?v=7WW3971s1Bg" target="_blank">
                <img src="' . $this->url_path . '/drupal-azure-sync-video-thumbnail.png" alt="video thumbnail"></a>')
        ];

        $form['overview_style_end'] = [
            '#markup' => t('</div>'),
        ];
    }

    private function AzureADStep2(array &$form, FormStateInterface $form_state){
        $form['azure_ad_step1_header_style'] = [
            '#markup' => t('<div class="mo_azure_header_container_step1">'),
        ];

        $this->guide_links($form);

        $form['azure_ad_step1_title'] = [
            '#markup' => t('<h2><u>STEP 2/3</u></h2><br><div class="mo_azure_ad_text_center"><h3>Please select how would you like to perform the sync with Azure AD</h3></div><br>')
        ];

        $rows = [
            [ Markup::create('<a href="configure_app/da"><div class="mo_azure_step_1_img mo_azure_ad_text_center"><img class="mo_azure_sync_gif" src="' . $this->url_path . '/drupal_ad_sync.gif" alt="Drupal to Azure AD Sync"></div></a>'), Markup::create('<a class="js-form-submit form-submit use-ajax mo_top_bar_button" data-dialog-type="modal" href="requestTrialAzure"><div class="mo_azure_step_1_img mo_azure_ad_text_center"><img class="mo_azure_sync_gif" src="' . $this->url_path . '/ad_drupal_sync.gif" alt="Azure AD to Drupal Sync"></div></a>')]
        ];

        $form['azure_ad_step1_how_to_sync'] = [
            '#type' => 'table',
            '#responsive' => TRUE,
            '#rows' => $rows,
            '#attributes' => ['style' => 'border-collapse: separate;', 'class' => ['how_to_perform_sync']],
        ];

        $form['mo_azure_ad_step2Backbutton'] = array(
            '#type' => 'submit',
            '#value' => t('&#11164; Back'),
            '#button_type' => 'danger',
            '#submit' => array('::AzureADStep2Backbutton'),
        );

        $form['azure_ad_step1_header_end'] = [
            '#markup' => t('</div>'),
        ];
    }

    private function AzureADStep1(array &$form, FormStateInterface $form_state){
        $form['azure_ad_step2_header_style'] = [
            '#markup' => t('<div class="mo_azure_header_container_step1">'),
        ];

        $this->guide_links($form);

        $form['mo_configure_azure_note']= [
            '#markup' => '<h2><u>STEP 1/3</u></h2><br><h3>Azure App Configuration</h3><hr><br><div class="mo_azure_highlight_background"><p>Configure the following settings to register your Azure AD/B2C application in Drupal.</p></div>',
        ];

        $this->AzureADConfigurationTable($form, $form_state);

        $form['configure_azure_step2_back_button'] = [
            '#type' => 'submit',
            '#value' => t('&#11164; Back'),
            '#button_type' => 'danger',
            '#limit_validation_errors' => [],
            '#prefix' => '<div class="container-inline">',
            '#submit' => ['::moAzureStep1BackButton'],
        ];

        $form['configure_azure_save_button'] = [
            '#type' => 'submit',
            '#value' => t('Save and Test Configuration'),
            '#button_type' => 'primary',
            '#submit' => ['::moAzureStep1SaveButton'],
        ];
        
        $azure_test_data = !empty($this->config->get('mo_azure_attr_list_from_server')) ? Json::decode($this->config->get('mo_azure_attr_list_from_server')) : '';
        if ( !empty($this->config->get('mo_azure_application_id')) && !empty($this->config->get('mo_azure_application_secret')) && !empty($this->config->get('mo_azure_tenant_id')) && !empty($this->config->get('mo_azure_tenant_name'))) {

            $form['configure_azure_step2_next_button'] = [
                '#type' => 'submit',
                '#value' => t('Next &#11166;'),
                '#button_type' => 'primary',
                '#attributes' => ['style' => 'float:right;'],
                '#disabled' => isset($azure_test_data['error|code']),
                '#submit' => ['::moAzureStep1NextButton'],
            ];

            if(!isset($azure_test_data['error|code'])){
              $form['manual_user_provisioning'] = array(
                '#markup' => '<a class="button button--primary js-form-submit mo_top_bar_button form-submit use-ajax formbutton" data-dialog-type="modal" data-dialog-options="{&quot;width&quot;:&quot;70%&quot;}" href="manualuserSync">Test User Sync</a>',
              );
            }

            $form['contianer_close'] = array(
                '#markup' => '</div>'
            );

            $this->moAzureTestResult($form, $form_state);
        }

        $form['azure_ad_step2_header_end'] = [
            '#markup' => t('</div></div></div>'),
        ];
    }

    private function AzureADStep3(array &$form, FormStateInterface $form_state){
        $form['azure_ad_step3_header_style'] = [
            '#markup' => t('<div class="mo_azure_header_container_step1">'),
        ];

        $this->guide_links($form);
        $form['mo_configure_azure_note']= [
            '#markup' => '<h2><u>STEP 3/3</u></h2><br><h3>Types of Provisioning</h3><hr><div class = "mo_azure_header_container_step2"><br><br>',
        ];

        if ($this->theme_name != 'claro'){
            $form['configure_azure_step3_break'] = [
                '#markup' => '<br>'
            ];
        }

        $form['azure_ad_step3_provisioning_types'] = [
            '#type' => 'table',
            '#responsive' => TRUE ,
            '#attributes' => ['class' => ['mo_azure_provisioning_types']],
        ];

        $data = ['description'];
        foreach ($data as $data_shown) {
            $row = $this->moAzureADProvisioningTypes($data_shown);
            $form['azure_ad_step3_provisioning_types'][$data_shown] = $row;
        }

        if ($this->theme_name != 'claro'){
            $form['configure_azure_step3_break2'] = [
                '#markup' => '<br>'
            ];
        }

        $form['azure_ad_Step3NextButton'] = array(
            '#type' => 'submit',
            '#button_type' => 'primary',
            '#value' => t('Next &#11166;'),
            '#attributes' => ['style' => 'float:right;'],
            '#submit' => array('::moAzureStep3NextButton'),
            '#prefix' => '<span>'
        );

        $form['azure_ad_Step3BackButton'] = array(
            '#type' => 'submit',
            '#button_type' => 'danger',
            '#value' => t(' &#11164; Back'),
            '#attributes' => ['style' => 'float:left;'],
            '#submit' => array('::moAzureStep3BackButton'),
            '#suffix' => '</span>'
        );

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

        $form['azure_ad_step3_header_end'] = [
            '#markup' => t('</div>'),
        ];

    }

    public function AzureADConfigurationTable(array &$form, FormStateInterface $form_state, $status = ''){
        if ($status == 'summary') {
            $form['azure_ad_summary_details']['mo_configure_azure_configuration'] = [
                '#type' => 'table',
                '#responsive' => TRUE,
                '#attributes' => ['style' => 'border-collapse: separate;'],
            ];
        }else{
            $form['mo_configure_azure_configuration'] = [
                '#type' => 'table',
                '#responsive' => TRUE,
                '#attributes' => ['style' => 'border-collapse: separate;'],
            ];
        }

        $data = $this->moDataConfigurations();

        $description_field = $this->moDataConfigurationNotes();

        foreach ($data as $key => $value) {
            $row = $this->moTableData($key, $value, $description_field);
            if ($status == 'summary'){
                $form['azure_ad_summary_details']['mo_configure_azure_configuration'][$key] = $row;
            }else {
                $form['mo_configure_azure_configuration'][$key] = $row;
            }
        }
    }

    public function AzureADTestConfigurationData($key, $value){

        $row[$key] = [
            '#type' => 'item',
            '#plain_text' => $key,
        ];

        $row[$value] = [
            '#type' => 'item',
            '#plain_text' => $value,
        ];

        return $row;
    }

    public function moAzureTestResult(array &$form, FormStateInterface $form_state){
        $azure_test_data = Json::decode($this->config->get('mo_azure_attr_list_from_server'));
  
        $form['azure_step2_test_data'] = array(
            '#type' => 'details',
            '#title' => $this->t('Test Configuration Result'),
            '#prefix' => '<div id="test_config_result">',
            '#open' => isset($azure_test_data["error|code"])
        );

        $form['azure_step2_test_data']['header_message'] = [
            '#markup' => isset($azure_test_data["error|code"]) ?
                $this->t('<div style="font-family:Calibri;padding:0 3%;">
                <div style="color: #a94442;background-color: #f2dede;padding: 15px;margin-bottom: 20px;text-align:center;border:1px solid #E6B3B2;font-size:18pt;">
                    ERROR
                </div><div style="color: #a94442;font-size:14pt; margin-bottom:20px;">') :
                $this->t('<div style="font-family:Calibri;padding:0 3%;"><div style="width:95%;color: #3c763d;background-color: #dff0d8;padding: 2%;margin-bottom: 20px;text-align: center;border: 1px solid #AEDB9A;font-size: 18pt;">
                    SUCCESS
                </div>'),
        ];

        if (isset($azure_test_data['Profile Picture'])) {
            $form['azure_step2_test_data']['profile_picture'] = [
                '#markup' => $this->t('<div style="text-align: center;"><img width="100px" height="100px" style=" max-height: 200px; display: inline-block;" src="' . Html::escape('data:image/jpeg;base64,' . $azure_test_data['Profile Picture']) . '" alt="profile image"></div><br>'),
            ];
        }

        $form['azure_step2_test_data']['azure_ad_step2_show_test_data'] = [
            '#type' => 'table',
            '#responsive' => true,
            '#attributes' => ['style' => 'border-collapse: separate;', 'class' => ['mo_azure_test_data']],
        ];

        foreach ($azure_test_data as $key => $value) {
            if ($key != 'Profile Picture') {
                $row = $this->AzureADTestConfigurationData($key, $value);
                $form['azure_step2_test_data']['azure_ad_step2_show_test_data'][$key] = $row;
            }
        }
    }

    private function moTableData($key, $value, $description_field){
        $row[$key.$key] = [
            '#markup' => '<div class="container-inline"><strong>'. $key . '</strong>',
        ];

        if ($key == 'Redirect URI: <span class="mo_redirect_uri">(Optional)</span> '){
            $row[$value] = [
                '#type' => 'item',
                '#plain_text' => $value,
            ];
        }else {
            $row[$value] = [
                '#type' => 'textfield',
                '#default_value' =>$this->config->get($value),
                '#required' => true,
                '#maxlength' => 1048,
                '#description' => $description_field[$key],
                '#suffix' => '</div>'
            ];
        }
        return $row;
    }

    public function moDataConfigurations(){

        global $base_url;

        $parsed_base_url = parse_url($base_url);
        $callbackUrl = 'https://' . $parsed_base_url['host'] . $parsed_base_url['path'];
        $this->config_factory->set('miniorange_auth_client_callback_uri', $callbackUrl)->save();

        return [
            'Tenant ID: ' => 'mo_azure_tenant_id',
            'Application (Client) ID: ' => 'mo_azure_application_id',
            'Client Secret: ' => 'mo_azure_application_secret',
            'Tenant Name/Primary Domain: ' => 'mo_azure_tenant_name',
            'Redirect URI: <span class="mo_redirect_uri">(Optional)</span> ' => $callbackUrl,
            'Test UPN/ID: ' => 'mo_azure_test_upn',
        ];
    }

    private function moDataConfigurationNotes(){
        return [
            'Tenant ID: ' => t('You can find the <strong>Tenant ID</strong> in the <strong>Overview</strong> tab of your Azure application.'),
            'Application (Client) ID: ' => t('You can find the <strong>Application ID</strong> in the <strong>Overview</strong> tab of your Azure application.'),
            'Client Secret: ' => t('You can find the <strong>Client Secret</strong> value in the <strong>Certificates & Secrets</strong> tab of your Azure application.'),
            'Tenant Name/Primary Domain: ' => t('You can find the <strong>Tenant Name</strong> under primary domain in the <strong>Overview</strong> tab of your Azure application.'),
            'Redirect URI: <span class="mo_redirect_uri">(Optional)</span> ' => t('This is your Drupal site URL'),
            'Test UPN/ID: ' => t('Please note that to test the configuration of your application you will need <strong>UserPrincipalName/ID</strong> of User. The <strong>User Principle Name / Object ID</strong> is present in the <strong>Users</strong> tab of your Azure Portal.'),
        ];
    }

    public function moAzureManualSync(array &$form, FormStateInterface $form_state){
        $sync = new MoDrupalToAzureSync();
        $sync->moAzureManualSync($form,$form_state);
    }

    public function moAzureStep1SaveButton(array &$form, FormStateInterface $form_state){
        $form_values = ($form_state->getValues())['mo_configure_azure_configuration'];
        $data = $this->moDataConfigurations();

        foreach ($data as $key => $value){
            $this->config_factory->set($value, $form_values[$key][$value])->save();
        }

        Drupal::configFactory()->getEditable('user_provisioning.settings')->set('mo_user_provisioning_configured_application', 'azure_ad')->save();

        $azure_ad_helper = new MoAzureADHelper();
        $azure_ad_helper->fetchAttributes();

        $azure_test_data = Json::decode($this->config->get('mo_azure_attr_list_from_server'));
        $this->config_factory->set('test_azure_config_result', isset($azure_test_data["error|code"]))->save();
        if (isset($azure_test_data["error|code"])){
            $this->messenger->addError(t('An error occurred while performing test configuration. Please refer to <a href="#test_config_result">Test Configuration Result</a> for more information.'));
        }else{
            if($this->config->get('azure_ad_provisioning_step') == 'azure_ad_user_provisioning')
              $this->messenger->addstatus(t('Test Configuration successful. You can check the complete list of attributes received from Azure AD by clicking on the link <a href="#test_config_result">HERE</a>. Now, you can perform user provisioning'));
            else
              $this->messenger->addstatus(t('Test Configuration successful. You can check the complete list of attributes received from Azure AD by clicking on the link <a href="#test_config_result">HERE</a>. Now, click on the <strong>Next</strong> button.'));
        }
    }

    public function moAzureStep1NextButton(array &$form, FormStateInterface $form_state){
        $this->config_factory
            ->set('azure_ad_provisioning_step', 'step2')
            ->save();
    }

    public function moAzureStep1BackButton(array &$form, FormStateInterface $form_state){
        $this->config_factory
            ->set('azure_ad_provisioning_step', '')
            ->save();
    }

    public function moAzureStep3BackButton(array &$form, FormStateInterface $form_state){
        $this->config_factory
            ->set('azure_ad_provisioning_step', 'step2')
            ->save();
    }

    public function moAzureStep3NextButton(array &$form, FormStateInterface $form_state){
        $this->config_factory->set('azure_ad_provisioning_step', 'azure_ad_user_provisioning')->save();
    }


    public function AzureADStep2Backbutton(array &$form, FormStateInterface $form_state){
        $this->config_factory
            ->set('azure_ad_provisioning_step', 'step1')
            ->save();
    }

    private function moAzureADProvisioningTypes($data){

        $row['azure_ad_manual_provisioning_button'] = [
            '#prefix' => '<div class="mo_azure_ad_text_center"><h4>Manual/On-Demand Provisioning</h4><hr></div>This will allow you to manually perform CRUD operations for any Drupal user in Azure AD.<br><br><div class="azure_ad_provisioning_button">',
            '#markup' => '<a class="button button--primary use-ajax" data-dialog-type="modal" data-dialog-options="{&quot;width&quot;:&quot;70%&quot;}" href="configuremanualprovisioning">&#9881; Configure</a>',
            '#suffix' => '</div>'
        ];

        $row['azure_ad_automatic_provisioning_button'] = [
            '#prefix' => '<div class="mo_azure_ad_text_center"><h4>Automatic Provisioning</h4><hr></div>This will allow you to automatically perform CRUD operations for any Drupal user in Azure AD when user registers/updates profile in your Drupal site.<br><br><div class="azure_ad_provisioning_button">',
            '#markup' => '<a id = "auto_prov_modal_link" class="button button--primary use-ajax" data-dialog-type="modal" data-dialog-options="{&quot;width&quot;:&quot;70%&quot;}" href="configureautomaticprovisioning">&#9881; Configure</a>',
            '#suffix' => '</div>'
        ];

        $row['azure_ad_scheduler_provisioning_button'] = [
            '#type' => 'submit',
            '#value' => t('&#9881; Configure'),
            '#disabled' => true,
            '#prefix' => '<div class="mo_azure_ad_text_center"><h4>Scheduler based Provisioning<a href="azure_upgrade_plans"><img class="mo_oauth_pro_icon1" src="' . $this->url_path . '/pro.png" alt="Premium"></a></h4><hr></div>This will allow you to perform CRUD operations for any Drupal user in Azure AD on the CRON.<br><br><div class="azure_ad_provisioning_button">',
            '#suffix' => '</div>'
        ];

        return $row;
    }

    public function guide_links(&$form){
        $form['markup_setup_guide_start'] = array(
            '#markup' => '<div class="container-inline">'
        );

        $form['markup_video_guide'] = array(
            '#markup' => '<a class="button button--primary mo-guides-floating" target="_blank" href="https://www.youtube.com/watch?v=7WW3971s1Bg">&#x23E9; Video Guide</a> '
        );

        $form['markup_setup_guide'] = array(
            '#markup' => '<a class="button button--primary mo-guides-floating" target="_blank" href="https://www.drupal.org/docs/contributed-modules/azure-drupal-sync">&#128366; Setup Guide</a>'
        );

        $form['markup_setup_guides_ends'] = array(
            '#markup' => '</div>'
        );
    }
}
