#include <3ds.h>
#include <citro2d.h>
#include <citro3d.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "gui.h"
#include "metadata.h"

static C3D_RenderTarget* topTarget = NULL;
static C3D_RenderTarget* bottomTarget = NULL;
static C2D_TextBuf textBuf = NULL;

/**
 * Initialize the GUI system
 */
int guiInit(void)
{
	gfxInitDefault();
	C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
	C2D_Init(C2D_DEFAULT_MAX_OBJECTS);
	C2D_Prepare();
	
	/* Create render targets for top and bottom screens */
	topTarget = C2D_CreateScreenTarget(GFX_TOP, GFX_LEFT);
	bottomTarget = C2D_CreateScreenTarget(GFX_BOTTOM, GFX_LEFT);
	
	if(!topTarget || !bottomTarget)
		return -1;
	
	/* Create text buffer */
	textBuf = C2D_TextBufNew(4096);
	if(!textBuf)
		return -1;
	
	return 0;
}

/**
 * Clean up and exit the GUI system
 */
void guiExit(void)
{
	if(textBuf)
		C2D_TextBufDelete(textBuf);
	
	C2D_Fini();
	C3D_Fini();
	gfxExit();
}

/**
 * Begin rendering a frame
 */
void guiBeginFrame(void)
{
	C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
}

/**
 * End rendering a frame and display it
 */
void guiEndFrame(void)
{
	C3D_FrameEnd(0);
}

/**
 * Clear the top screen
 */
void guiClearTopScreen(void)
{
	C2D_TargetClear(topTarget, GUI_COLOR_BG_TOP);
}

/**
 * Clear the bottom screen
 */
void guiClearBottomScreen(void)
{
	C2D_TargetClear(bottomTarget, GUI_COLOR_BG_BOTTOM);
}

/**
 * Draw a simple text string at specified position
 * @param screen	Screen to draw on (GFX_TOP or GFX_BOTTOM)
 * @param x		X position
 * @param y		Y position
 * @param text	Text string to draw
 * @param color	Text color
 * @param scale	Text scale
 */
void guiDrawText(gfxScreen_t screen, float x, float y, const char* text, u32 color, float scale)
{
	if(!text || !textBuf)
		return;
	
	C2D_Text c2dText;
	C2D_TextBufClear(textBuf);
	C2D_TextParse(&c2dText, textBuf, text);
	C2D_TextOptimize(&c2dText);
	
	C3D_RenderTarget* target = (screen == GFX_TOP) ? topTarget : bottomTarget;
	C2D_SceneBegin(target);
	C2D_DrawText(&c2dText, C2D_WithColor, x, y, 0.5f, scale, scale, color);
}

/**
 * Display metadata on the top screen
 * @param metadata	Pointer to metadata structure to display
 * @param filename	Filename to display if no title is available
 */
void guiDisplayMetadata(struct metadata_t* metadata, const char* filename)
{
	if(!metadata || !filename || !textBuf)
		return;
	
	C2D_SceneBegin(topTarget);
	
	/* Extract just the filename without path and extension for fallback */
	const char* basename = strrchr(filename, '/');
	if(!basename)
		basename = filename;
	else
		basename++;
	
	/* Remove file extension for display */
	char displayName[64];
	strncpy(displayName, basename, sizeof(displayName) - 1);
	displayName[sizeof(displayName) - 1] = '\0';
	char* dot = strrchr(displayName, '.');
	if(dot) *dot = '\0';
	
	C2D_Text text;
	float y = 10.0f;
	float scale = 0.6f;
	float lineHeight = 20.0f;
	
	C2D_TextBufClear(textBuf);
	
	/* Draw title */
	if(metadata->title[0])
	{
		char titleBuf[64];
		snprintf(titleBuf, sizeof(titleBuf), "%.47s", metadata->title);
		C2D_TextParse(&text, textBuf, titleBuf);
		C2D_TextOptimize(&text);
		C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, scale, scale, GUI_COLOR_TEXT);
	}
	else
	{
		char titleBuf[64];
		snprintf(titleBuf, sizeof(titleBuf), "%.47s", displayName);
		C2D_TextParse(&text, textBuf, titleBuf);
		C2D_TextOptimize(&text);
		C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, scale, scale, GUI_COLOR_TEXT);
	}
	y += lineHeight;
	
	/* Draw artist */
	if(metadata->artist[0])
	{
		char artistBuf[64];
		snprintf(artistBuf, sizeof(artistBuf), "%.45s", metadata->artist);
		C2D_TextParse(&text, textBuf, artistBuf);
		C2D_TextOptimize(&text);
		C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, scale * 0.8f, scale * 0.8f, GUI_COLOR_TEXT_DIM);
	}
	else
	{
		C2D_TextParse(&text, textBuf, "Unknown Artist");
		C2D_TextOptimize(&text);
		C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, scale * 0.8f, scale * 0.8f, GUI_COLOR_TEXT_DIM);
	}
	y += lineHeight;
	
	/* Draw album */
	if(metadata->album[0])
	{
		char albumBuf[64];
		snprintf(albumBuf, sizeof(albumBuf), "%.45s", metadata->album);
		C2D_TextParse(&text, textBuf, albumBuf);
		C2D_TextOptimize(&text);
		C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, scale * 0.8f, scale * 0.8f, GUI_COLOR_TEXT_DIM);
	}
	else
	{
		C2D_TextParse(&text, textBuf, "Unknown Album");
		C2D_TextOptimize(&text);
		C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, scale * 0.8f, scale * 0.8f, GUI_COLOR_TEXT_DIM);
	}
}

/**
 * Display log messages on the top screen
 * @param messages	Array of log message strings
 * @param count		Number of messages in the array
 * @param scroll	Index of first visible message for scrolling
 */
void guiDisplayLog(const char** messages, int count, int scroll)
{
	if(!messages || count <= 0 || !textBuf)
		return;
	
	C2D_SceneBegin(topTarget);
	
	C2D_Text text;
	float y = 70.0f; /* Start below metadata area */
	float scale = 0.4f;
	float lineHeight = 12.0f;
	int maxLines = 14;
	
	C2D_TextBufClear(textBuf);
	
	for(int i = scroll; i < count && (i - scroll) < maxLines; i++)
	{
		if(messages[i])
		{
			C2D_TextParse(&text, textBuf, messages[i]);
			C2D_TextOptimize(&text);
			C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, scale, scale, GUI_COLOR_TEXT);
			y += lineHeight;
		}
	}
}

/**
 * Display file list on the bottom screen
 * @param files		Array of file/folder names
 * @param count		Number of entries in the array
 * @param selected	Index of currently selected entry
 * @param scroll	Index of first visible entry for scrolling
 */
void guiDisplayFileList(const char** files, int count, int selected, int scroll)
{
	if(!files || count <= 0 || !textBuf)
		return;
	
	C2D_SceneBegin(bottomTarget);
	
	C2D_Text text;
	float y = 18.0f; /* Start below path display */
	float scale = 0.5f;
	float lineHeight = 16.0f;
	int maxLines = 13; /* One less line due to path at top */
	
	C2D_TextBufClear(textBuf);
	
	for(int i = scroll; i < count && (i - scroll) < maxLines; i++)
	{
		if(files[i])
		{
			/* Check if this is a directory */
			size_t len = strlen(files[i]);
			bool isDir = (len > 0 && files[i][len-1] == '/');
			
			/* Draw selection highlight */
			if(i == selected)
			{
				C2D_DrawRectSolid(5.0f, y - 2.0f, 0.5f, 310.0f, lineHeight, GUI_COLOR_HIGHLIGHT);
			}
			
			/* Truncate if too long */
			char displayName[48];
			snprintf(displayName, sizeof(displayName), "%.40s", files[i]);
			
			C2D_TextParse(&text, textBuf, displayName);
			C2D_TextOptimize(&text);
			
			/* Use different color for directories */
			u32 color;
			if(i == selected)
				color = GUI_COLOR_ACCENT;
			else if(isDir)
				color = C2D_Color32(100, 200, 255, 255); /* Light blue for folders */
			else
				color = GUI_COLOR_TEXT;
			
			C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, scale, scale, color);
			y += lineHeight;
		}
	}
}

/**
 * Display playback controls and status on the top screen
 * @param isPlaying		Whether playback is active
 * @param isPaused		Whether playback is paused
 * @param position		Current playback position in seconds
 * @param duration		Total duration in seconds
 */
void guiDisplayPlaybackStatus(bool isPlaying, bool isPaused, float position, float duration)
{
	if(!textBuf)
		return;
	
	C2D_SceneBegin(topTarget);
	
	C2D_Text text;
	C2D_TextBufClear(textBuf);
	
	/* Display status and time at bottom of top screen */
	float y = 215.0f;
	
	/* Display status */
	char statusBuf[64];
	if(isPlaying)
	{
		if(isPaused)
			snprintf(statusBuf, sizeof(statusBuf), "Paused");
		else
			snprintf(statusBuf, sizeof(statusBuf), "Playing");
	}
	else
	{
		snprintf(statusBuf, sizeof(statusBuf), "Stopped");
	}
	
	C2D_TextParse(&text, textBuf, statusBuf);
	C2D_TextOptimize(&text);
	C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.5f, 0.5f, GUI_COLOR_TEXT);
	
	/* Display time if playing */
	if(isPlaying && duration > 0)
	{
		char timeBuf[32];
		int posMin = (int)position / 60;
		int posSec = (int)position % 60;
		int durMin = (int)duration / 60;
		int durSec = (int)duration % 60;
		snprintf(timeBuf, sizeof(timeBuf), "%02d:%02d / %02d:%02d", posMin, posSec, durMin, durSec);
		
		C2D_TextParse(&text, textBuf, timeBuf);
		C2D_TextOptimize(&text);
		C2D_DrawText(&text, C2D_WithColor, 280.0f, y, 0.5f, 0.5f, 0.5f, GUI_COLOR_TEXT);
	}
}

/**
 * Display version text and credits at bottom of bottom screen
 * @param version	Version string to display
 */
void guiDisplayVersion(const char* version)
{
	if(!textBuf)
		return;
	
	C2D_SceneBegin(bottomTarget);
	
	C2D_Text text;
	C2D_TextBufClear(textBuf);
	
	/* Display "mice - by sillyangel" at bottom center */
	char credits[64];
	if(version && version[0])
		snprintf(credits, sizeof(credits), "mice %s - by sillyangel", version);
	else
		snprintf(credits, sizeof(credits), "mice - by sillyangel");
	C2D_TextParse(&text, textBuf, credits);
	C2D_TextOptimize(&text);
	C2D_DrawText(&text, C2D_WithColor, 80.0f, 220.0f, 0.5f, 0.45f, 0.45f, GUI_COLOR_TEXT_DIM);
}

/**
 * Display progress bar on the top screen
 * @param position	Current playback position in seconds
 * @param duration	Total duration in seconds
 */
void guiDisplayProgressBar(float position, float duration)
{
	if(duration <= 0)
		return;
	
	C2D_SceneBegin(topTarget);
	
	/* Progress bar at bottom of top screen */
	float barY = 205.0f;
	float barX = 10.0f;
	float barWidth = 380.0f;
	float barHeight = 6.0f;
	
	/* Background bar */
	C2D_DrawRectSolid(barX, barY, 0.5f, barWidth, barHeight, C2D_Color32(50, 50, 60, 255));
	
	/* Progress fill */
	float progress = position / duration;
	if(progress > 1.0f) progress = 1.0f;
	if(progress < 0.0f) progress = 0.0f;
	
	float fillWidth = barWidth * progress;
	if(fillWidth > 0)
	{
		C2D_DrawRectSolid(barX, barY, 0.5f, fillWidth, barHeight, GUI_COLOR_ACCENT);
	}
}

/**
 * Display current directory path on bottom screen
 * @param path	Current directory path
 */
void guiDisplayCurrentPath(const char* path)
{
	if(!path || !textBuf)
		return;
	
	C2D_SceneBegin(bottomTarget);
	
	C2D_Text text;
	C2D_TextBufClear(textBuf);
	
	/* Display path at top of bottom screen */
	char pathBuf[64];
	snprintf(pathBuf, sizeof(pathBuf), "%.55s", path);
	
	C2D_TextParse(&text, textBuf, pathBuf);
	C2D_TextOptimize(&text);
	C2D_DrawText(&text, C2D_WithColor, 5.0f, 2.0f, 0.5f, 0.35f, 0.35f, GUI_COLOR_TEXT_DIM);
}
