<?php

namespace App\Helpers;

use App\Models\TobescrappedCandidate;
use DOMDocument;
use DOMElement;
use DOMXPath;
use Illuminate\Support\Facades\Log;

class SourceCodeHelper
{
    public static function getSourceCodeFromUrl($url,$render = true)
    {
        $scraperApiKey = '6b804350e3cae8bdbeb49a0cde637e94';
        $scraperApiUrl = 'http://api.scraperapi.com';
         $url = "{$scraperApiUrl}?api_key={$scraperApiKey}&url=" . urlencode($url) . "&render={$render}";
        //$url = "{$scraperApiUrl}?api_key={$scraperApiKey}&url=" . urlencode($url);

        return \Illuminate\Support\Facades\Http::withHeaders([
            'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
            'Accept-Encoding' => 'gzip, deflate, br',
            'Accept-Language' => 'en-US,en;q=0.9',
            'Cache-Control' => 'no-cache',
            'Pragma' => 'no-cache',
            'Sec-Fetch-Dest' => 'document',
            'Sec-Fetch-Mode' => 'navigate',
            'Sec-Fetch-Site' => 'none',
            'Sec-Fetch-User' => '?1',
            'Upgrade-Insecure-Requests' => '1',
            'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36',
        ])
        ->withOptions([
            'allow_redirects' => [
                'max' => 10,
                'strict' => true,
                'referer' => true,
                'track_redirects' => true
            ]
        ])
        ->timeout(300)
        ->withoutVerifying()
        ->get($url);
    }

    public static function getCandidateSourceCode($url,$firm,$render = true)
    {
        $response = self::getSourceCodeFromUrl($url,$render);
        if($firm->not_found_page_404_header == 1) {
            $notFoundByHeader = self::checkNotFoundPageWithHeader($response);
            if($notFoundByHeader) {
                Log::channel('candidate_source_code')->info('Not found page found by header for: ' . $url);
                return false;
            }
        }
        $notFoundByTitle = self::checkNotFoundPageWithTitle($response,$firm);
        if($notFoundByTitle) {
            Log::channel('candidate_source_code')->info('Not found page found by title for: ' . $url);
            return false;
        }
        return $response->body();
    }

    public static function cleanSourceCode($sourceCode, $firm)
    {
        $doc = new DOMDocument();
        libxml_use_internal_errors(true);
        $doc->loadHTML($sourceCode);
        libxml_clear_errors();
        $xpath = new DOMXPath($doc);
        if($firm->firmPatterns->isNotEmpty()) {
            foreach($firm->firmPatterns as $pattern) {
                $nodes = $xpath->query($pattern->pattern);
                foreach ($nodes as $node) {
                    $node->parentNode->removeChild($node);
                }
            }
        }
        $addiontionalPatterns = self::fixedPatterns();
        foreach ($addiontionalPatterns as $addiontionalPattern) {
            $nodes = $xpath->query($addiontionalPattern);
            foreach ($nodes as $node) {
                $node->parentNode->removeChild($node);
            }
        }

        $elements = $xpath->query('//*[@style]');
        foreach ($elements as $el) {
            if ($el instanceof DOMElement) {
                $el->removeAttribute('style');
            }
        }
        $sourceCode = $doc->saveHTML();

        if(!empty($firm->container_pattern)) {
            $doc = new DOMDocument();
            libxml_use_internal_errors(true);
            $doc->loadHTML($sourceCode);
            libxml_clear_errors();
            $xpath = new DOMXPath($doc);
            $node = $xpath->query($firm->container_pattern)->item(0);
            if ($node) {
                $sourceCode = $doc->saveHTML($node);
            }
        }
        return $sourceCode;
    }

    public static function checkNotFoundPageWithHeader($response)
    {
        $status = $response->status();
        return in_array($status, [404, 410, 500, 502, 503, 504]);
    }

    public static function checkNotFoundPageWith404Header($response)
    {
        $status = $response->status();
        return in_array($status, [404]);
    }


    public static function checkNotFoundPageWithTitle($response,$firm,$specific = false)
    {
        $sourceCode = $response->body();
        $doc = new DOMDocument();
        libxml_use_internal_errors(true);
        $doc->loadHTML($sourceCode);
        libxml_clear_errors();
        $xpath = new DOMXPath($doc);
        $titleNode = $xpath->query('//title')->item(0);
        $title = $titleNode ? trim($titleNode->textContent) : null;
        if ($title) {
            if($specific) {
                $keywords = self::getSpecific404Keywords();
            } else {
                $keywords = self::getAll404Keywords();
            }
            if($firm->not_found_page_title!='') {
                array_push($keywords, strtolower($firm->not_found_page_title));
            }
            $found = false;
            foreach ($keywords as $keyword) {
                if (stripos($title, $keyword) !== false) {
                    $found = true;
                    break;
                }
            }
            return $found;
        }
        return true;
    }

    public static function getSpecific404Keywords()
    {
        return [
            '404',
            'not found',
            'page not found',
            'error page',
            'error 404',
            '404 not found',
            'sorry, the page',
        ];
    }

    public static function getAll404Keywords()
    {
        return [
            '404',
            'not found',
            'page not found',
            'error page',
            'error 404',
            '404 not found',
            'just a moment',
            'invocation failed',
            'gateway time-out',
            'bad gateway',
            'internal server error',
            'sorry, the page',
            'access denied'
        ];
    }

    protected static function fixedPatterns()
    {
        return [
            '//script',
            '//style',
            '//input',
            '//noscript',
            '//link',
            '//meta',
            '//iframe',
            '//object',
            '//embed',
            '//param',
            '//canvas',
            '//svg',
            '//video',
            '//audio',
            '//picture',
            '//source',
            '//track',
            '//map',
            '//button',
            '//comment()'
        ];
    }

    public static function removeCandidateFromURlFilePool($bioUrl)
    {
        TobescrappedCandidate::where('url', $bioUrl)->delete();
    }
}
