import {
	appDataDir,
	join,
	basename as pathBasename,
	dirname as pathDirname
} from '@tauri-apps/api/path';
import { stat, mkdir, readDir, copyFile, rename, remove, exists } from '@tauri-apps/plugin-fs';
import { open } from '@tauri-apps/plugin-dialog';
import baseicon from '$lib/assets/baseicon.png';
import europa from '$lib/assets/fonts/Europa-Mono-Medium.otf';
import { BASE_LIBRARY_DIR } from './settings';
import figlet from 'figlet';
import shadow from 'figlet/fonts/Classy';
import { getInstalledVersions, getTemplatesDir } from './library';
figlet.parseFont('Big', shadow);

/**
 * Create a custom icon with text overlay
 * @param {string} [iconText] - Text to overlay on the icon
 * @returns {Promise<Blob>} Promise resolving to a PNG blob of the icon
 */
export async function createIcon(iconText) {
	// Create canvas element
	const canvas = document.createElement('canvas');
	const ctx = canvas.getContext('2d');

	const img = new Image();
	img.src = baseicon;

	await new Promise((resolve) => {
		img.onload = resolve;
	});

	canvas.width = img.width;
	canvas.height = img.height;

	ctx.drawImage(img, 0, 0);

	ctx.fillStyle = '#7d70ba';
	ctx.textAlign = 'left';
	ctx.textBaseline = 'top';

	const fontFace = new FontFace('Europa-Mono', `url(${europa})`);
	await fontFace.load();
	document.fonts.add(fontFace);

	const fontSize = canvas.width / 6;
	ctx.font = `${fontSize}px Europa-Mono`;

	const text = iconText || 'XXX';
	ctx.fillText(text, 150, 150);

	return new Promise((resolve) => {
		canvas.toBlob((blob) => {
			resolve(blob);
		}, 'image/png');
	});
}

/**
 * Create a custom banner with version number next to the baseIcon image
 * @param {string} text - Version text to display
 * @returns {Promise<Blob>} Promise resolving to a PNG blob of the banner
 */
export async function createBanner(text) {
	// Create canvas element for banner
	const canvas = document.createElement('canvas');
	const ctx = canvas.getContext('2d');

	// Set banner dimensions
	canvas.width = 600;
	canvas.height = 90;

	// Draw background
	ctx.fillStyle = '#171a21';
	ctx.fillRect(0, 0, canvas.width, canvas.height);

	// Load and draw base icon
	const img = new Image();
	img.src = baseicon;

	await new Promise((resolve) => {
		img.onload = resolve;
	});

	// Add version text
	ctx.fillStyle = '#f5f5f5';
	ctx.textAlign = 'left';
	ctx.textBaseline = 'middle';

	const fontFace = new FontFace('Europa-Mono', `url(${europa})`);
	await fontFace.load();
	document.fonts.add(fontFace);
	const fontSize = 10;
	ctx.font = `${fontSize}px Europa-Mono`;

	// Position text to the right of the icon
	const textX = 20;
	const textY = canvas.height / 2;

	const bannerText = await figlet.text(text, {
		font: 'Big'
	});
	const lines = bannerText.split('\n');
	const lineHeight = fontSize * 1.2;
	const startY = textY - (lines.length * lineHeight) / 2 + lineHeight / 2;

	ctx.font = `${fontSize}px monospace`;
	ctx.textAlign = 'left';
	ctx.textBaseline = 'top';

	lines.forEach((line, index) => {
		ctx.fillText(line, textX, startY + index * lineHeight);
	});

	return new Promise((resolve) => {
		canvas.toBlob((blob) => {
			resolve(blob);
		}, 'image/png');
	});
}

export async function addTemplateFile(version, filePath) {
  const newFileName = await pathBasename(filePath);
  const templateName = newFileName.replace(/\.blend$/i, '');
  const newTemplatePath = await join(await getTemplatesDir(version), templateName);

	// Check for duplicate template name
	if (await exists(newTemplatePath)) {
		return { success: false, message: `Template "${templateName}" already exists` };
	}

  const newTemplateFile = await join(newTemplatePath, 'startup.blend');
  await ensureDirectory(newTemplatePath);

	try {
		await copyFile(filePath, newTemplateFile);
	} catch (error) {
		console.error('Error adding template file:', error);
		return { success: false, message: `Failed to add template: ${error.message || error}` };
	}

	await getInstalledVersions();

	return { success: true, message: `Template "${templateName}" added` };
}

/**
 * Create library directory structure if it doesn't exist
 * @param {string} libraryDir - Library directory path
 * @returns {Promise<void>}
 */
export async function ensureLibraryStructure(libraryDir) {
	try {
		const baseDir = await join(libraryDir, BASE_LIBRARY_DIR);
		const blenderDir = await join(baseDir, 'blender');
		await mkdir(blenderDir, { recursive: true });
		const configDir = await join(baseDir, 'config');
		await mkdir(configDir, { recursive: true });

		console.log('Library structure created at:', libraryDir);
	} catch (error) {
		console.error('Error creating library structure:', error);
		throw error;
	}
}

/**
 * Open a directory picker dialog for selecting a directory.
 * @param {string} [currentPath] - Current path to use as default
 * @returns {Promise<string|null>} Selected path or null if cancelled
 */
export async function selectDirectory(currentPath) {
	try {
		// Use currentPath if proided, otherwise use app data directory
		let defaultPath = await appDataDir();
		if (currentPath) {
			defaultPath = currentPath;
		}

		const selected = await open({
			multiple: false,
			recursive: true,
			directory: true,
			title: 'Select Library Directory',
			defaultPath
		});

		return selected;
	} catch (error) {
		console.error('Error opening directory picker:', error);
		return null;
	}
}

/**
 * Check if a directory exists
 * @param {string} path - Directory path to check
 * @returns {Promise<boolean>} True if directory exists
 */
export async function directoryExists(path) {
	try {
		const stats = await stat(path);
		return stats.isDirectory;
	} catch {
		return false;
	}
}

/**
 * Create a directory recursively if it doesn't exist
 * @param {string} path - Directory path to create
 * @returns {Promise<void>}
 */
export async function ensureDirectory(path) {
	try {
		await mkdir(path, { recursive: true });
	} catch (error) {
		console.error(`Error creating directory ${path}:`, error);
		throw error;
	}
}

/**
 * Copy a file or directory recursively
 * @param {string} source - Source path
 * @param {string} destination - Destination path
 * @returns {Promise<void>}
 */
export async function copyPath(source, destination) {
	try {
		const statInfo = await stat(source);
		if (statInfo.isDirectory) {
			// Create destination directory
			await mkdir(destination, { recursive: true });
			// Read all entries in source
			const entries = await readDir(source);
			for (const entry of entries) {
				const srcPath = await join(source, entry.name);
				const destPath = await join(destination, entry.name);
				await copyPath(srcPath, destPath); // recursive call
			}
		} else {
			// It's a file, copy directly
			await copyFile(source, destination);
		}
	} catch (error) {
		console.error(`Error copying ${source} to ${destination}:`, error);
		throw error;
	}
}

/**
 * Move or rename a file or directory
 * @param {string} source - Source path
 * @param {string} destination - Destination path
 * @returns {Promise<void>}
 */
export async function movePath(source, destination) {
	try {
		await rename(source, destination);
	} catch (error) {
		console.error(`Error moving ${source} to ${destination}:`, error);
		throw error;
	}
}

/**
 * Strip top-level directory if the target directory contains only one subdirectory.
 * This is useful after extracting archives that create an unnecessary parent folder.
 * @param {string} targetDir - Directory to check and potentially flatten
 * @returns {Promise<boolean>} True if flattening was performed, false otherwise
 */
export async function stripTopLevelDirectory(targetDir) {
	try {
		// Read contents of target directory
		const entries = await readDir(targetDir);

		// If there's exactly one entry and it's a directory, flatten it
		if (entries.length === 1 && entries[0].isDirectory) {
			const singleDirName = entries[0].name;
			const singleDirPath = await join(targetDir, singleDirName);

			// Read contents of the single subdirectory
			const subEntries = await readDir(singleDirPath);

			// Move all items from subdirectory to target directory
			for (const entry of subEntries) {
				const sourcePath = await join(singleDirPath, entry.name);
				const destPath = await join(targetDir, entry.name);
				await rename(sourcePath, destPath);
			}

			// Remove the now-empty subdirectory
			await remove(singleDirPath, { recursive: true });

			console.log(`Flattened directory structure: removed ${singleDirName}/`);
			return true;
		}

		return false;
	} catch (error) {
		console.error(`Error stripping top-level directory in ${targetDir}:`, error);
		throw error;
	}
}
