// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+

#pragma once

#include "ui_DisassemblyView.h"

#include "Debugger/DebuggerView.h"
#include "Debugger/NavigationHistoryStack.h"

#include "pcsx2/DebugTools/DisassemblyManager.h"

#include <QtWidgets/QMenu>
#include <QtGui/QPainter>

class DisassemblyView final : public DebuggerView
{
	Q_OBJECT

public:
	DisassemblyView(const DebuggerViewParameters& parameters);
	~DisassemblyView();

	void toJson(JsonValueWrapper& json) override;
	bool fromJson(const JsonValueWrapper& json) override;

	// Required for the breakpoint list (ugh wtf)
	QString GetLineDisasm(u32 address);

	bool supportsNavigation() override;
	bool canNavigateBack() override;
	bool canNavigateForward() override;
	void navigateBack() override;
	void navigateForward() override;

protected:
	void paintEvent(QPaintEvent* event) override;
	void mousePressEvent(QMouseEvent* event) override;
	void mouseDoubleClickEvent(QMouseEvent* event) override;
	void wheelEvent(QWheelEvent* event) override;
	void keyPressEvent(QKeyEvent* event) override;

public slots:
	void openContextMenu(QPoint pos);

	// Context menu actions
	// When called, m_selectedAddressStart will be the 'selected' instruction
	// Of course, m_selectedAddressEnd will be the end of the selection when required
	void contextCopyAddress();
	void contextCopyInstructionHex();
	void contextCopyInstructionText();
	void contextCopyFunctionName();
	void contextPasteInstructionText();
	void contextAssembleInstruction();
	void contextNoopInstruction();
	void contextRestoreInstruction();
	void contextRunToCursor();
	void contextJumpToCursor();
	void contextToggleBreakpoint();
	void contextFollowBranch();
	void contextGoToAddress();
	void contextAddFunction();
	void contextRenameFunction();
	void contextRemoveFunction();
	void contextStubFunction();
	void contextRestoreFunction();
	void contextShowInstructionBytes();

	void gotoAddressAndSetFocus(u32 address);
	void gotoProgramCounterOnPause();
	void gotoAddress(u32 address, bool should_set_focus);

	void toggleBreakpoint(u32 address);

private:
	Ui::DisassemblyView m_ui;

	u32 m_visibleStart = STARTING_ADDRESS; // The address of the first instruction shown.
	u32 m_visibleRows;
	u32 m_selectedAddressStart = 0;
	u32 m_selectedAddressEnd = 0;
	u32 m_rowHeight = 0;

	std::map<u32, u32> m_nopedInstructions;
	std::map<u32, std::tuple<u32, u32>> m_stubbedFunctions;

	bool m_showInstructionBytes = true;
	bool m_goToProgramCounterOnPause = true;
	DisassemblyManager m_disassemblyManager;

	NavigationHistoryStack<u32> m_navigation_history{STARTING_ADDRESS};

	QString GetDisassemblyTitleLine();
	QColor GetDisassemblyTitleLineColor();
	inline QString DisassemblyStringFromAddress(u32 address, QFont font, u32 pc, bool selected);
	QColor GetAddressFunctionColor(u32 address);
	enum class SelectionInfo
	{
		ADDRESS,
		INSTRUCTIONHEX,
		INSTRUCTIONTEXT,
	};
	QString FetchSelectionInfo(SelectionInfo selInfo);

	void setInstructions(u32 start, u32 end, u32 value);
	bool AddressCanRestore(u32 start, u32 end);
	bool FunctionCanRestore(u32 address);

	static constexpr u32 STARTING_ADDRESS = 0x100000;
};
