<?php

namespace Drupal\abinbev_gmap;

use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ConfigFactory;
use \Drupal\Core\Database\Connection;
use Drupal\Core\Logger\LoggerChannelFactory;
use GuzzleHttp\Client;

/**
 * Class PlaceInfoService
 *
 * @package Drupal\abinbev_gmap\Services
 */
class PlaceInfoService {

  protected $config;
  protected $importConfig;

  protected $logger;

  protected $client;

  protected $database;

  protected $userDataService;

  protected $cache;

  /**
   * CustomService constructor.
   */
  public function __construct(ConfigFactory $config, LoggerChannelFactory $logger, Client $client, Connection $database, UserDataService $userDataService, CacheBackendInterface $cache) {
    $this->config = $config->get('abinbev_gmap.settings');
    $this->importConfig = $config->get('abinbev_gmap.import_locations');
    $this->logger = $logger;
    $this->client = $client;
    $this->database = $database;
    $this->userDataService = $userDataService;
    $this->cache = $cache;
  }

  /**
   * @param $place
   *
   * @return mixed|\Psr\Http\Message\ResponseInterface|string
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  function getPlaceInfoFromGoogleByAdress($place) {
    $result = '';
    $api_key = $this->config->get('google_api_key');

    if (is_array($place)) {
      $address = $place[1] . ', ' . $place[2] . ', ' . $place[3];
    }
    else {
      $address = $place;
    }

    //$url = 'https://maps.googleapis.com/maps/api/geocode/json?address=' . $address . '&key=' . $api_key;
    $url = 'https://maps.googleapis.com/maps/api/geocode/json?address=' . $address . '&key=' . $api_key;
    try {
      $result = $this->client->request('GET', $url);
      $result = json_decode($result->getBody(), TRUE);

      if (!isset($result['status'])) {
        \Drupal::logger("NOT STATUS")
          ->error('<pre>' . print_r($result, 1) . '</pre>');
      }
      if ($result['status'] == "ZERO_RESULTS") {
        $preferred_country = $this->importConfig->get('preferred_country');
        $region = '';
        if (!empty($preferred_country)) {
          $region = '&region=' . $preferred_country;
        }
        $url = 'https://maps.googleapis.com/maps/api/place/textsearch/json?query='. $address . $region . '&key=' . $api_key;

        \Drupal::logger("Zero result URL")->warning(print_r($url, 1));
        try {
          $result = $this->client->request('GET', $url);
          $result = json_decode($result->getBody(), TRUE);

          if (!empty($result['candidates'])) {
            $result = $this->getPlaceInfoFromGoogle($result['candidates'][0]['place_id']);
            \Drupal::logger("place id result")->warning(print_r($result, 1));
            return $result['results'];
          }
        }
        catch (\Exception $e) {
          \Drupal::messenger()->addError($e->getMessage());
          \Drupal::logger("GOOGLE RESULT second fail")
            ->error('<pre>' . print_r($e->getMessage(), 1) . '</pre>');
        }

      }
      if ($result['status'] != '"REQUEST_DENIED"') {
        return $result['results'];
      }
    }
    catch (\Exception $e) {
      \Drupal::messenger()->addError($e->getMessage());
    }
    return $result;
  }

  /**
   * Get Place Info.
   */
  public function getPlaceInfoFromGoogle($place_id) {
    $api_key = $this->config->get('google_api_key');

    $result = FALSE;
    $url = 'https://maps.googleapis.com/maps/api/place/details/json?key=' . $api_key . '&place_id=' . $place_id;

    try {
      $result = $this->client->request('GET', $url);
      $result = json_decode($result->getBody(), TRUE);
      if (!isset($result['status'])) {
        \Drupal::logger("NOT STATUS")
          ->error('<pre>' . print_r($result, 1) . '</pre>');
      }
      if ($result['status'] != '"REQUEST_DENIED"') {
        return $result['result'];
      }
    }
    catch (\Exception $e) {
      \Drupal::messenger()->addError($e->getMessage());
    }

    return $result;
  }

  /**
   * @param $poc_id
   * @param $data
   *
   * @return \Drupal\Core\Database\StatementInterface|int|string|null
   * @throws \Exception
   */
  function getPlaceData($poc_id) {
    $connection = $this->database;
    $query = $connection->select('map_place_info', 'bi')
      ->fields('bi', [])
      ->condition('poc_id', $poc_id)
      ->execute();
    return $query->fetchAssoc();
  }

  /**
   * Get Place by ID.
   *
   * @param $place_id
   *
   * @return array
   */
  function getPlaceDataByPlaceId($place_id) {
    $connection = $this->database;
    $query = $connection->select('map_place_info', 'bi')
      ->fields('bi', [])
      ->condition('place_id', $place_id)
      ->execute();
    return $query->fetchAll();
  }

  /**
   * @param $title
   *
   * @return void
   */
  function deleteLocation($poc_id) {
    $connection = $this->database;

    $connection->delete('map_place_info')
      ->condition('poc_id', $poc_id)
      ->execute();

    $view = \Drupal\views\Views::getView('gmap_locations_list');
    $view->storage->invalidateCaches();
  }

  /**
   * Insert Data to DB.
   *
   * @param $data
   */
  function saveData($place_id, $data, $isPlace = FALSE) {
    $connection = $this->database;
    if (!$isPlace) {
      /** @var \Drupal\Core\Database\Query\Query $query */
      $query = $connection->insert('map_place_info');
    }
    else {
      $query = $connection->update('map_place_info');
    }
    $query->fields([
      'place_id' => $place_id,
      'poc_id' => $data['poc_id'],
      'title' => $data['title'],
//      'address' => $data['address'],
      'lat' => $data['lat'],
      'lon' => $data['lon'],
      'full_info' => $data['full_info'],
      'category' => $data['category'],
      'status' => $data['status'],
    ]);

    if ($isPlace) {
      $query->condition('poc_id', $data['poc_id']);
    }

    $r = $query->execute();

    return $r;
  }

  /**
   * Truncate All Data.
   *
   * @return int|null
   */
  function truncateData() {
    $connection = $this->database;
    $query = $connection->truncate('map_place_info')
      ->execute();
    return $query;
  }

  /**
   * @return mixed
   */
  function getAllPlaces($update_cache = FALSE) {
    $connection = $this->database;
    $cid = 'all_map_info';
    $data = NULL;
    if (!$update_cache) {
      if ($cache = $this->cache->get($cid)) {
        $data = $cache->data;
      }
      else {
        $query = $connection->select('map_place_info', 'pi')
          ->fields('pi', [])
          ->condition('status', 'Published')
          ->execute();
        $data = $query->fetchAll();

        $this->cache->set($cid, $data);
      }
    }
    else {
      $query = $connection->select('map_place_info', 'pi')
        ->fields('pi', [])
        ->condition('status', 'Published')
        ->execute();
      $data = $query->fetchAll();

      $this->cache->set($cid, $data);
    }
    return $data;
  }

  /**
   * @return mixed
   */
  function getSelectedPlaces($ids) {
    if (empty($ids)) {
      return [];
    }

    if (!is_array($ids)) {
      $ids = [$ids];
    }

    //$res = views_get_view_result('gmap_locations_list', 'block_1');
    //$cid = 'all_map_info:' . implode(',', $ids);

    //    $data = NULL;
    //    if ($cache = $this->cache->get($cid)) {
    //      $data = $cache->data;
    //    }
    //else {
    $connection = $this->database;
    $query = $connection->select('map_place_info', 'pi')
      ->fields('pi', [])
      ->condition('poc_id', $ids, 'IN')
      //->condition('status', 'Published')
      ->execute();
    $data = $query->fetchAll();

    // $this->cache->set($cid, $data);
    //}

    return $data;
  }

  /**
   * @param $place_id, $poc_id
   *
   * @return \Drupal\Core\Database\StatementInterface|int|string|null
   * @throws \Exception
   */
  function savePlace($place_id, $poc_id) {
    $this->cache->invalidate('all_map_info');
    $placeInfo = $this->getPlaceData($poc_id);
    if (!$placeInfo) {
      $place = $this->getPlaceInfoFromGoogle($place_id);
      if (!empty($place['name'])) {
        $values = [
          'place_id' => $place_id,
          'poc_id' => $poc_id,
          'title' => $place['name'],
          'lat' => $place['geometry']['location']['lat'],
          'lon' => $place['geometry']['location']['lng'],
          'full_info' => json_encode($place),
          'status' => 'Published',
        ];
        $placeInfo = $this->saveData($place_id, $values);
      }
      else {
        \Drupal::logger('Place has no Name')->error(print_r($place_id, 1));
      }
    }
    return $placeInfo;
  }

}
