<?php

namespace OtomaticAi\Controllers\SingleMode;

use Exception;
use OtomaticAi\Controllers\Controller;
use OtomaticAi\Utils\RobotsTxt;
use OtomaticAi\Vendors\GuzzleHttp\Client;
use OtomaticAi\Vendors\GuzzleHttp\Pool;
use OtomaticAi\Vendors\GuzzleHttp\Psr7\Request;
use OtomaticAi\Vendors\GuzzleHttp\Psr7\Response;
use OtomaticAi\Vendors\vipnytt\SitemapParser;

class SitemapSourceController extends Controller
{
    public function search()
    {
        $this->validate([
            "url" => ["required", "url"],
        ]);

        try {

            // get sitemap
            $parser = new SitemapParser();
            $parser->parse($this->input('url'));

            $urls = array_keys($parser->getURLs());

            // get urls titles
            $titles = $this->getUrlsTitles($urls);

            $this->response($titles);
        } catch (Exception $e) {
            $this->response(["message" => "An error occurred", "error" => $e->getMessage()], 503);
        }
    }

    private function getUrlsTitles(array $urls): array
    {
        $output = [];

        // create the client
        $client = new Client(
            [
                "headers" => [
                    "User-Agent" => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36',
                ]
            ]
        );

        // make the requests
        $requests = [];
        foreach ($urls as $url) {
            if (!$this->isDisabledByRobotsTxt($url)) {
                $requests[] = new Request(
                    'GET',
                    $url,
                );
            }
        }

        // create the pool
        $pool = new Pool($client, $requests, [
            'concurrency' => 20,
            'fulfilled' => function (Response $response, $index) use (&$output, $urls) {
                $response = $response->getBody()->getContents();
                // h1
                $title = preg_match('/<h1[^>]*>(.*?)<\/h1>/ims', $response, $matches) ? $matches[1] : null;
                if (!empty($urls[$index]) && !empty($title)) {
                    $output[$index] = [
                        "title" => mb_convert_encoding($title, 'UTF-8', 'UTF-8'),
                        "url" => mb_convert_encoding($urls[$index], 'UTF-8', 'UTF-8'),
                    ];
                } else {
                    // title
                    $title = preg_match('/<title[^>]*>(.*?)<\/title>/ims', $response, $matches) ? $matches[1] : null;
                    if (!empty($urls[$index]) && !empty($title)) {
                        $output[$index] = [
                            "title" => mb_convert_encoding($title, 'UTF-8', 'UTF-8'),
                            "url" => mb_convert_encoding($urls[$index], 'UTF-8', 'UTF-8'),
                        ];
                    }
                }
            },
            'rejected' => function (Exception $reason, $index) {},
        ]);

        // call the pool
        $promise = $pool->promise();
        $promise->wait();

        // sort and get only values
        ksort($output);

        return array_values($output);
    }

    /**
     * Determine if the scrap is disabled by the robots.txt
     *
     * @param string $url
     * @return boolean
     */
    private function isDisabledByRobotsTxt(string $url)
    {
        $robots = RobotsTxt::fromUrl($url);
        return !empty($robots->getRules("otomaticAI"));
    }
}
