/* SPDX-License-Identifier: GPL-3.0-or-later
 * SPDX-FileCopyrightText: 2022-2025 Soren Stoutner <soren@stoutner.com>
 *
 * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <https://www.gnu.org/licenses/>.
 */

// Application headers.
#include "UrlRequestInterceptor.h"
#include "GlobalVariables.h"
#include "helpers/FilterListHelper.h"
#include "structs/RequestStruct.h"

// KDE Framework headers.
#include <KLocalizedString>

// Construct the class.
UrlRequestInterceptor::UrlRequestInterceptor(PrivacyWebEngineView *privacyWebEngineViewPointer) :
                                             QWebEngineUrlRequestInterceptor(privacyWebEngineViewPointer), privacyWebEngineViewPointer(privacyWebEngineViewPointer) {}

void UrlRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &urlRequestInfo)
{
    // Clear the requests list if a main frame resource is being loaded.
    if (urlRequestInfo.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeMainFrame)
        Q_EMIT newMainFrameResource();

    // Create a requests struct.
    RequestStruct *requestStructPointer = new RequestStruct;

    // Store the basic request information.
    requestStructPointer->navigationTypeInt = urlRequestInfo.navigationType();
    requestStructPointer->requestMethodString = QLatin1String(urlRequestInfo.requestMethod());
    requestStructPointer->resourceTypeInt = urlRequestInfo.resourceType();
    requestStructPointer->urlString = urlRequestInfo.requestUrl().toString();
    requestStructPointer->webPageUrlString = urlRequestInfo.firstPartyUrl().toString();

    // Create a continue processing flag.
    bool continueProcessing = true;

    // Block certain resource types.
    switch (urlRequestInfo.resourceType())
    {
        case QWebEngineUrlRequestInfo::ResourceTypePrefetch:
        {
            // Block the request.
            urlRequestInfo.block(true);

            // Mark the request struct as blocked.
            requestStructPointer->dispositionInt = FilterListHelper::BLOCKED;

            // Describe the prefetch request as blocked by the default behavior.
            requestStructPointer->filterListTitle = i18nc("Default prefetch blocking", "Default blocking of all prefetch requests.");

            // Set the continue processing flag.
            continueProcessing = false;

            break;
        }

        case QWebEngineUrlRequestInfo::ResourceTypeCspReport:
        {
            // Block the request.
            urlRequestInfo.block(true);

            // Mark the request struct as blocked.
            requestStructPointer->dispositionInt = FilterListHelper::BLOCKED;

            // Describe the CSP request as blocked by the default behavior.
            requestStructPointer->filterListTitle = i18nc("Default CSP blocking", "Default blocking of all CSP requests.");

            // Set the continue processing flag.
            continueProcessing = false;

            break;
        }

        case QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadMainFrame:
        case QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadSubFrame:
        {
            // Block the request.
            urlRequestInfo.block(true);

            // Mark the request struct as blocked.
            requestStructPointer->dispositionInt = FilterListHelper::BLOCKED;

            // Describe the preload request as blocked by the default behavior.
            requestStructPointer->filterListTitle = i18nc("Default preload blocking", "Default blocking of all preload requests.");

            // Set the continue processing flag.
            continueProcessing = false;

            break;
        }

        default:
        {
            // Do nothing.
            break;
        }
    }

    // Check the filter lists if it hasn't already been handled.
    if (continueProcessing)
        continueProcessing = globalFilterListHelperPointer->checkFilterLists(privacyWebEngineViewPointer, urlRequestInfo, requestStructPointer);

    // Further process the request if it hasn't already been handled.
    if (continueProcessing) {
        // Handle the request according to the resource type.
        switch (urlRequestInfo.resourceType())
        {
            // A naughty HTTP ping request.
            case QWebEngineUrlRequestInfo::ResourceTypePing:
            {
                // Block the HTTP ping request.
                urlRequestInfo.block(true);

                // Mark the request struct as blocked.
                requestStructPointer->dispositionInt = FilterListHelper::BLOCKED;

                // Describe the ping as blocked by the default behavior.
                requestStructPointer->filterListTitle = i18nc("Default HTTP ping blocking", "Default blocking of all HTTP ping requests.");

                // Set the continue processing flag.
                continueProcessing = false;

                // Display the HTTP Ping blocked dialog.
                Q_EMIT displayHttpPingDialog(urlRequestInfo.requestUrl().toString());

                break;
            }

            default:
            {
                // Do nothing.
                break;
            }
        }
    }

    // Handle the request according to the navigation type if it hasn't already been handled.
    if (continueProcessing)
    {
        switch (urlRequestInfo.navigationType())
        {
            case QWebEngineUrlRequestInfo::NavigationTypeLink:
            case QWebEngineUrlRequestInfo::NavigationTypeTyped:
            case QWebEngineUrlRequestInfo::NavigationTypeFormSubmitted:
            case QWebEngineUrlRequestInfo::NavigationTypeRedirect:
            case QWebEngineUrlRequestInfo::NavigationTypeOther:
            {
                // Only check the hosts if the main URL is changing.
                if (urlRequestInfo.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeMainFrame)
                {
                    // Get the request URL.
                    QUrl requestUrl = urlRequestInfo.requestUrl();

                    // Reapply the domain settings if the host is changing.
                    if (privacyWebEngineViewPointer->currentHost != requestUrl.host())
                    {
                        // Apply domain settings, after which the request will be loaded.  `false` indicates that history is not being navigated.
                        Q_EMIT applyDomainSettings(requestUrl, false);

                        // Block this copy of the request.
                        urlRequestInfo.block(true);
                    }
                }

                break;
            }

            case QWebEngineUrlRequestInfo::NavigationTypeBackForward:
            {
                // Only check the hosts if the main URL is changing.
                if (urlRequestInfo.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeMainFrame)
                {
                    // Get the request URL.
                    QUrl requestUrl = urlRequestInfo.requestUrl();

                    // Reapply the domain settings if the host is changing.
                    if (privacyWebEngineViewPointer->currentHost != requestUrl.host())
                    {
                        // Apply domain settings, after which the request will be loaded.  `true` indicates that history is being navigated.
                        Q_EMIT applyDomainSettings(requestUrl, true);
                    }
                }

                break;
            }

            default:
            {
                // Do nothing.
                break;
            }
        }
    }

    // Send the request struct to the privacy WebEngine view.
    Q_EMIT requestProcessed(requestStructPointer);
}
