#include "c.h"
#include "filesystem.h"
#include "helper.h"
#include "target.h"
#include "tier0/lib.h"
#include "tier0/platform.h"
#include "tier1/utlvector.h"
#include "libgen.h"
#include "ctype.h"

struct ClangFile_t
{
	CUtlString m_szName;
	CUtlVector<CUtlString> m_szArguments;
};

CUtlVector<ClangFile_t> g_clangFiles;

CLDProject CCProject::Compile()
{
	CLDProject proj = {};
	proj.m_szName = m_szName;
	unsigned int hash = GenerateProjectHash();
	for (auto &file: files)
	{
		CUtlVector<CUtlString> args;
		V_printf("  CC     %s\n", file.GetString());
		CUtlString szTarget = m_target.GetTriplet();
		CUtlString szOutputFile = CUtlString("%s/%s/cc/%u_%s/%s/%s.o",FPC_TEMPORAL_DIRNAME, szTarget.GetString(), hash, m_szName.GetString(), IFileSystem2::BuildDirectory(), file.GetString());
		CUtlString szOutputDir;

		args = {
			"-target",
			szTarget,
			"-g",
			"-c",
			"-o",
			szOutputFile,
			file,
		};
		if (!strcmp(Plat_GetExtension(file),"cpp"))
			args.AppendTail("-std=c++17"); 
		else
			args.AppendTail("-std=c99"); 

		if (m_target.kernel == TARGET_KERNEL_DARWIN)
		{
			args.AppendTail("-isysroot");
			args.AppendTail("/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk");
		}
		if (m_target.kernel == TARGET_KERNEL_IOS)
		{
			args.AppendTail("-isysroot");
			args.AppendTail("/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk");
			args.AppendTail("-miphoneos-version-min=18.0 ");
			args.AppendTail("-fembed-bitcode");
		}
		if (bFPIC)
			args.AppendTail("-fPIC");
		if (bFPIE)
			args.AppendTail("-fPIE");
		for (auto &macro: macros)
		{
			args.AppendTail("-D");
			args.AppendTail(CUtlString("%s=%s", (char*)macro.szName, (char*)macro.szValue));
		}
		for (auto &include: includeDirectories)
		{
			args.AppendTail("-I");
			args.AppendTail(include);
		}
		for (auto &include: includeFiles)
		{
			args.AppendTail("-include");
			args.AppendTail(include);
		}
		if (!IFileSystem2::ShouldRecompile(file, szOutputFile))
			goto skipcompile;
		szOutputDir = szOutputFile;
		szOutputDir = dirname(szOutputDir);
		IFileSystem2::MakeDirectory(szOutputDir);
		IRunner::Run("clang", args);

skipcompile:
		proj.objects.AppendTail((CObject){szOutputFile});

		ClangFile_t cfile = {};
		cfile.m_szName = file;
		cfile.m_szArguments = args;
		g_clangFiles.AppendTail(cfile);
	}
	return proj;
}

void CCProject::GenerateCompileCommands()
{
	FILE* f = V_fopen("compile_commands.json", "w");
	V_fprintf(f, "[\n");
	uint32_t i = 0;
	for (auto &file: g_clangFiles)
	{
		V_fprintf(f, "\t{\n");
		V_fprintf(f, "\t\t\"arguments\": [\n");
		V_fprintf(f, "\t\t\t\"clang\",\n");
		for (auto &arg: file.m_szArguments)
			V_fprintf(f, "\t\t\t\"%s\",\n",arg.GetString());
	
		V_fseek(f, -2, SEEK_CUR);
		V_fprintf(f, "\n\t\t],\n");
		V_fprintf(f, "\t\t\"file\": \"%s\",\n", file.m_szName.GetString());
		V_fprintf(f, "\t\t\"directory\": \"%s\"\n", IFileSystem2::BuildDirectory());
		V_fprintf(f, "\t},\n");
	};
	V_fseek(f, -2, SEEK_CUR);
	V_fprintf(f, "\n]\n");
	V_fclose(f);
};
