<?php

namespace Drupal\lingotek\Controller;

use Drupal\Component\Serialization\Json;
use Drupal\lingotek\Form\LingotekSettingsAccountForm;
use Drupal\lingotek\Form\LingotekSettingsCommunityForm;
use Drupal\lingotek\Form\LingotekSettingsConnectForm;
use Drupal\lingotek\Form\LingotekSettingsDefaultsForm;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

/**
 * Returns responses for lingotek module setup routes.
 */
class LingotekSetupController extends LingotekControllerBase {

  /**
   * Presents a connection page to Lingotek Services
   *
   * @return array
   *   The connection form.
   */
  public function accountPage() {
    if ($this->setupCompleted()) {
      return $this->formBuilder->getForm(LingotekSettingsAccountForm::class);
    }
    return [
      '#type' => 'markup',
      'markup' => $this->formBuilder->getForm(LingotekSettingsConnectForm::class),
    ];
  }

  public function handshake(Request $request) {
    $access_token = $request->get('access_token');
    if ($access_token != NULL and $access_token != "") {     
      $accountConfig = \Drupal::configFactory()->getEditable('lingotek.account');

      //Keep track of old access token to restore it if the new one is invalid
      $old_access_token = $accountConfig->get('access_token');

      //save new access token, poll account info and save it 
      $accountConfig->set('access_token', $access_token);
      $accountConfig->save();
      $account_info = $this->fetchAccountInfo();
      $this->saveAccountInfo($account_info);

      //if newly saved token/info is valid, proceed to community page 
      if ($accountConfig->get('access_token') and $account_info) {
        $this->logger->notice('Account connected to Lingotek.');
        $this->messenger()->addStatus($this->t('Your account settings have been saved.'));
        return $this->redirect('lingotek.setup_community');
      }

      \Drupal::messenger()->deleteAll();
      //if new token/info is invalid, poll account info for old token
      $accountConfig->set('access_token', $old_access_token);
      $accountConfig->save();
      $account_info = $this->fetchAccountInfo();

      // if old token's info is valid, save it the corresponding account info      
      if($account_info){
        $this->saveAccountInfo($account_info);
        \Drupal::messenger()->addError(t('Your configuration has not been changed. Please try again.'));  
      }
      else{
        //if old token's info is invalid, wipe out the invalid token and info from system
        $accountConfig->set('access_token', null);
        $accountConfig->save();
        $this->saveAccountInfo(null);
        \Drupal::messenger()->addError(t('Invalid access token. This indicates either no access token has been set up yet or that the previously used token has expired. Kindly generate a new access token using the link provided in the section below.'));
      }
      return $this->redirect('lingotek.access_token_update');      
    }
    return new JsonResponse([
      'status' => FALSE,
      'message' => 'Account not connected to Lingotek.',
    ]);
  }

  public function communityPage() {
    if ($redirect = $this->checkSetup()) {
      $this->messenger()->deleteAll();
      $this->messenger()->addError($this->t('There was a problem connecting your account. Please ensure your access token is valid. If unsure, please generate a new access token from the link provided in the section below.'));
      return $redirect;
    }
    $communities = $this->lingotek->getCommunities(TRUE);
    if (empty($communities)) {
      $this->logger->error('Account not connected to Lingotek.');
      return $this->redirect('lingotek.access_token_update');
    }
    $accountConfig = \Drupal::configFactory()->getEditable('lingotek.account');
    $accountConfig->set('resources.community', $communities);
    $accountConfig->save();
    if (count($communities) == 1) {
      // No choice necessary. Save and advance to next page.
      $accountConfig->set('default.community', current(array_keys($communities)));
      $accountConfig->save();
      // update resources based on newly selected community
      $this->lingotek->getResources(TRUE);
      return $this->redirect('lingotek.setup_defaults');
    }
    return [
      '#type' => 'markup',
      'markup' => $this->formBuilder->getForm(LingotekSettingsCommunityForm::class),
    ];
  }

  public function defaultsPage() {
    if ($redirect = $this->checkSetup()) {
      return $redirect;
    }
    $resources = $this->lingotek->getResources();
    // No choice necessary. Save and advance to the next page.
    if (count($resources['project']) == 1 && count($resources['vault']) == 1) {
      $accountConfig = \Drupal::configFactory()->getEditable('lingotek.account');

      $accountConfig->set('default.project', current(array_keys($resources['project'])));
      $accountConfig->set('default.vault', current(array_keys($resources['vault'])));
      $default_workflow = array_search('Machine Translation', $resources['workflow']);
      if ($default_workflow === FALSE) {
        $default_workflow = current(array_keys($resources['workflow']));
      }
      $accountConfig->set('default.workflow', $default_workflow);
      // Assign the project callback
      $new_callback_url = \Drupal::urlGenerator()->generateFromRoute('lingotek.notify', [], ['absolute' => TRUE]);
      $accountConfig->set('callback_url', $new_callback_url);
      $accountConfig->save();
      $default_project = $accountConfig->get('default.project');
      $new_response = $this->lingotek->setProjectCallBackUrl($default_project, $new_callback_url);
      if ($new_response) {
        $this->pushProjectCallbackCredentials($default_project, $new_callback_url);
      }
      return $this->redirect('lingotek.dashboard');
    }
    return [
      '#type' => 'markup',
      'markup' => $this->formBuilder->getForm(LingotekSettingsDefaultsForm::class),
    ];
  }

  protected function saveToken($token) {
    if (!empty($token)) {
      \Drupal::configFactory()->getEditable('lingotek.account')->set('access_token', $token)->save();
    }
  }

  protected function saveAccountInfo($account_info) {
    if (!empty($account_info)) {
      $accountConfig = \Drupal::configFactory()->getEditable('lingotek.account');
      $accountConfig->set('login_id', $account_info['login_id']);
      $accountConfig->save();
    }
  }

  protected function fetchAccountInfo() {
    return $this->lingotek->getAccountInfo();
  }

}
