// -----------------------------------------------------------------------------
// radar.cpp
// -----------------------------------------------------------------------------
// Implementation of the minimap radar. The thread walks the 64 player
// controller slots, resolves each pawn through m_hPlayerPawn and marks
// enemies as spotted. Walking the controller chain (instead of a raw
// identity scan) guarantees the pawn pointers are valid before the write.
// The bomb entities (carried/dropped C4 + planted C4) are spotted with
// the same flag so the bomb icon shows on the minimap for both teams.
// When the radar is toggled off the previously set flags are cleared
// exactly once; afterwards the thread rests without touching memory.
// -----------------------------------------------------------------------------

#include "radar.h"

#include <windows.h>
#include <sstream>

#include "../config.h"
#include "../util/logger.h"

namespace features {

void Radar::Initialize(const core::ProcessMemory* memory, const core::GameOffsets* offsets,
	const sdk::EntityList* entities, const sdk::LocalPlayer* player)
{
	m_memory = memory;
	m_offsets = offsets;
	m_entities = entities;
	m_player = player;
}

void Radar::Start()
{
	CreateThread(nullptr, 0, &Radar::ThreadProc, this, 0, nullptr);
}

unsigned long __stdcall Radar::ThreadProc(void* param)
{
	Radar* self = static_cast<Radar*>(param);
	if (self == nullptr) {
		return 1;
	}

	while (true) {
		if (!cfg::g_config.radarEnabled) {
			if (self->m_lastEnabled) {
				self->ClearSpotted();
				self->m_lastEnabled = false;
			}
			Sleep(500);
			continue;
		}
		self->m_lastEnabled = true;

		const uintptr_t meBase = self->m_player->GetLocalPawn();
		if (meBase == 0) {
			Sleep(10);
			continue;
		}

		const int myTeam = self->m_player->GetTeam();
		if (myTeam != 2 && myTeam != 3) {
			Sleep(10);
			continue;
		}

		int markedCount = 0;
		for (int i = 0; i < sdk::kMaxPlayers; i++) {
			const uintptr_t pawn = self->m_entities->GetPawn(i);
			if (pawn == 0 || pawn == meBase) {
				continue;
			}

			if (!self->m_entities->IsValidPawn(pawn, myTeam)) {
				continue;
			}

			std::stringstream ss;
			ss << "[radar] spot slot=" << i << " pawn=0x" << std::hex << pawn
				<< " addr=0x" << (pawn + self->m_offsets->entitySpottedState + self->m_offsets->spotted);
			util::LogDebug(ss.str());
			self->m_memory->Write<bool>(pawn + self->m_offsets->entitySpottedState + self->m_offsets->spotted, 1);
			markedCount++;
		}

		if (markedCount > 0) {
			util::LogDebug("[radar] marked " + std::to_string(markedCount) + " enemies");
		}

		self->SpotBombs();

		Sleep(10);
	}
	return 0;
}

void Radar::ScanBombs()
{
	const int c4Index = m_entities->FindEntityByClassName("C_C4");
	m_c4Entity = (c4Index >= 0) ? m_entities->GetRawEntity(c4Index) : 0;
	m_c4Identity = (c4Index >= 0) ? m_entities->GetIdentityAddress(c4Index) : 0;

	const int plantedIndex = m_entities->FindEntityByClassName("C_PlantedC4");
	m_plantedC4Entity = (plantedIndex >= 0) ? m_entities->GetRawEntity(plantedIndex) : 0;
	m_plantedC4Identity = (plantedIndex >= 0) ? m_entities->GetIdentityAddress(plantedIndex) : 0;

	std::stringstream ss;
	ss << "[radar] bomb scan: c4=0x" << std::hex << m_c4Entity
		<< " plantedC4=0x" << m_plantedC4Entity;
	util::LogDebug(ss.str());
}

void Radar::SpotBomb(uintptr_t entity, uintptr_t identity, uintptr_t spottedStateOffset, bool value)
{
	if (entity == 0 || identity == 0 || spottedStateOffset == 0 || m_offsets->spotted == 0) {
		return;
	}
	if (m_memory->Read<uintptr_t>(identity) != entity) {
		return;
	}
	m_memory->Write<bool>(entity + spottedStateOffset + m_offsets->spotted, value);
}

void Radar::SpotBombs()
{
	if (GetTickCount() - m_lastBombScan > 1000) {
		m_lastBombScan = GetTickCount();
		ScanBombs();
	}

	SpotBomb(m_c4Entity, m_c4Identity, m_offsets->c4SpottedState, true);
	SpotBomb(m_plantedC4Entity, m_plantedC4Identity, m_offsets->plantedC4SpottedState, true);
}

void Radar::ClearSpotted()
{
	const int localTeam = m_player->GetTeam();
	const uintptr_t meBase = m_player->GetLocalPawn();
	for (int i = 0; i < sdk::kMaxPlayers; i++) {
		const uintptr_t pawn = m_entities->GetPawn(i);
		if (pawn == 0 || pawn == meBase) {
			continue;
		}
		if (!m_entities->IsValidPawn(pawn, localTeam)) {
			continue;
		}
		m_memory->Write<bool>(pawn + m_offsets->entitySpottedState + m_offsets->spotted, 0);
	}

	SpotBomb(m_c4Entity, m_c4Identity, m_offsets->c4SpottedState, false);
	SpotBomb(m_plantedC4Entity, m_plantedC4Identity, m_offsets->plantedC4SpottedState, false);
}

} // namespace features