<?php

namespace Modules\Seo\Controllers;

use Google\Exception;
use Google_Service_Indexing_UrlNotification;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Modules\Seo\Models\GoogleIndex;

class IndexController extends BaseController
{
    protected $credentials = null;
    protected $endpoints = [
        'METADATA' => 'https://indexing.googleapis.com/v3/urlNotifications/metadata',
        'PUBLISH' => 'https://indexing.googleapis.com/v3/urlNotifications:publish',
        'BATCH' => 'https://indexing.googleapis.com/batch'
    ];
    protected $client = null;
    protected $batchClient = null;
    protected $indexService = null;
    protected $httpClient = null;

    public function __construct()
    {
        $this->credentials = app_path('Modules/Seo/google-credentials.json');
    }

    /**
     * @throws Exception
     */
    protected function getBatchClient()
    {
        if(!$this->batchClient) {
            $client = new \Google_Client();

            $client->setAuthConfig($this->credentials);
            $client->addScope('https://www.googleapis.com/auth/indexing');
            $client->setUseBatch(true);
            $client->authorize();

            $service = $this->getIndexService($client);

            $this->batchClient = $service->createBatch();
        }

        return $this->batchClient;
    }

    /**
     * @throws Exception
     */
    protected function getClient()
    {
        if(!$this->client) {
            $client = new \Google_Client();

            $client->setAuthConfig($this->credentials);
            $client->addScope('https://www.googleapis.com/auth/indexing');
            $client->authorize();

            $this->client = $client;
        }

        return $this->client;
    }

    /**
     * @throws Exception
     */
    protected function getHttpClient()
    {
        if (!$this->httpClient) {
            $client = new \Google_Client();
            $client->setAuthConfig($this->credentials);
            $client->addScope('https://www.googleapis.com/auth/indexing');
            $this->httpClient = $client->authorize();
        }

        return $this->httpClient;
    }

    protected function getIndexService($client)
    {
        if (!$this->indexService) {
            $this->indexService = new \Google_Service_Indexing($client);
        }
        return $this->indexService;
    }

    protected function addRequest($url, $type = 'URL_UPDATED')
    {
        $postBody = new \Google_Service_Indexing_UrlNotification();
        $postBody->setType($type);
        $postBody->setUrl($url);
        $this->batchClient->add($this->indexService->urlNotifications->publish($postBody));
    }

    public function indexLink(Request $request)
    {
        $links = $request->input('links');
        $response = [
            'result' => []
        ];

        if ($links) {
            try {
                foreach($links as $link) {
                    $response['result'][] = [
                        'url' => $link,
                        'status' => $this->index($link)
                    ];
                }
            } catch (\Exception $_) {
                $response['message'] = $_->getMessage();
            }
        }

        return $response;
    }

    public function indexProduct(Request $request)
    {
        $productIds = $request->input('ids');
        $response = [
            'result' => []
        ];

        if ($productIds) {
            $productIds = explode(',', $productIds);
            $productIds = array_map(function($id) {
                return trim($id);
            }, $productIds);
            try {
                $products = DB::table('product')->whereIn('id', $productIds)
                    ->select(['id', 'slug'])
                    ->get();
                foreach($products as $product) {
                    $url = route('product', ['slug' => $product->slug, 'id' => $product->id]);
                    $response['result'][] = $this->index($url);
                }
            } catch (\Exception $_) {
                $response['message'] = $_->getMessage();
            }
        }

        return $response;
    }

    /**
     * @throws Exception
     */
    public function index($pageUrl)
    {
        $client = $this->getClient();
        $indexService = $this->getIndexService($client);
        return $this->publish($indexService, $pageUrl);
    }

    protected function publish($indexService, $pageUrl, $type = 'URL_UPDATED')
    {
        return $indexService->urlNotifications->publish(new Google_Service_Indexing_UrlNotification([
            'url' => $pageUrl,
            'type' => $type
        ]));
    }

    /**
     * @throws Exception
     */
    public function getStatus(Request $request)
    {
        $url = $request->input('url');

        $this->getHttpClient();
        $status = $this->httpClient->get($this->endpoints['METADATA'] . '?url=' . urlencode($url));

        response()->json($status->getBody());
    }

    public function indexTool(Request $request) {

        $urls = $request->input('link');
        $msg = [];
        if ($urls) {
            $urls = explode("\n", $urls);
            $urls = array_map(function($url) {
                return trim($url);
            }, $urls);

            foreach($urls as $url) {
                try {
                    if (filter_var($url, FILTER_VALIDATE_URL) === FALSE) {
                        throw new Exception('Not a valid URL!');
                    }
                    if ($this->checkExistUrl($url)) {
                        throw new Exception('URL Exist!');
                    }
                    $result = $this->index($url);
                    if ($result && $result->urlNotificationMetadata->url) {
                        $this->persistUrl($url);
                        $msg[] = [
                            'class' => 'success',
                            'text' => 'SUCCESS: ' . $url
                        ];
                    }
                } catch (\Exception $e) {
                    $msg[] = [
                        'class' => 'danger',
                        'text' => "ERROR: " . $url . '<br>' . $e->getMessage()
                    ];
                }
            }

        }

        $googleIndexs = GoogleIndex::query()->paginate(50);

        return view('seo::indexing/index', [
            'msg' => $msg,
            'googleIndexs' => $googleIndexs
        ]);
    }

    private function checkExistUrl($url) {
        $hash = hash('sha256', $url);
        return GoogleIndex::query()->where('hash_url', $hash)->exists();
    }

    private function persistUrl($url) {
        $hash = hash('sha256', $url);
        return GoogleIndex::query()->insert([
            'url' => $url,
            'hash_url' => $hash,
            'created_at' => date('Y-m-d H:i:s'),
            'updated_at' => date('Y-m-d H:i:s'),
        ]);
    }

    public function setting() {
        return view('seo::admin.setting');
    }

    public function settingMeta() {
        return view('seo::admin.setting-meta');
    }
    public function redirect() {
        return view('seo::admin.redirect.index');
    }

    public function metaData() {
        return view('seo::admin.meta-data.index');
    }
    public function tagConfig() {
        return view('seo::admin.tag-config.index');
    }

    public function faq() {
        return view('seo::admin.faq.index');
    }

    public function hreflang() {
        return view('seo::admin.hreflang.index');
    }

    public function optionFilterLink() {
        return view('seo::admin.option-filter-link.index');
    }
}