import { fetch } from '@tauri-apps/plugin-http';
import { platform } from '@tauri-apps/plugin-os';
import { currentSettings } from './settings';
import { writable } from 'svelte/store';
import { get } from 'svelte/store';

const RELEASES_URL = 'https://download.blender.org/release/';

/**
 * @typedef {Object} FileLink
 * @property {string} version - The version string (e.g., "5.0.0")
 * @property {string} downloadUrl - The full download URL
 * @property {string} platform - The platform identifier (e.g., 'linux', 'windows', 'macos')
 * @property {string} architecture - The architecture identifier (e.g., 'x64', 'arm64')
 * @property {string} fileExtension - The file extension (e.g., 'tar.xz', 'zip')
 * @property {string} status - The download status ('pending', 'downloading', 'completed', 'error')
 * @property {number} percent - The download progress percentage (0-100)
 */

/**
 * @typedef {Object} BlenderRelease
 * @property {string} original - The original href from the release page
 * @property {string} version - The version string (e.g., "2.80", "3.6", "4.2alpha")
 * @property {string} fullPath - The full URL to the release folder
 * @property {Date|null} lastModified - The last modified date (currently null)
 * @property {Array<FileLink>} links - Array of download links for this release
 */

export const blenderReleases = writable([]);

export async function getBlenderReleases() {
	const settings = await get(currentSettings);
	const currentPlatform = settings.defaultPlatform || platform();
	const currentArch = settings.defaultArch;
	try {
		// Fetch the HTML page
		const response = await fetch(RELEASES_URL);
		const html = await response.text();

		// Parse the HTML
		const parser = new DOMParser();
		const doc = parser.parseFromString(html, 'text/html');

		// Extract all links that look like version folders
		const links = doc.querySelectorAll('a');
		/** @type {Promise<any>[]} */
		const folderPromises = [];

		links.forEach((link) => {
			const href = link.getAttribute('href');
			// Filter for directory links (ending with '/') that are version folders
			// This regex matches patterns like Blender2.80/, Blender3.6/, Blender4.2alpha/, etc.
			if (href && href.endsWith('/') && href.match(/^Blender[\d.]+[a-z]*\//)) {
				// Remove the trailing slash and 'Blender' prefix for cleaner version names
				const versionName = href.slice(0, -1).replace('Blender', ''); // Remove trailing slash
				if (parseFloat(versionName) > 2.78) {
					const promise = getBlenderMinorVersionsWithDownload(
						`https://download.blender.org/release/${href}`,
						currentPlatform,
						currentArch
					).then((links) => {
						// Only add to array if there are links
						if (links && links.length > 0) {
							return {
								original: href,
								version: versionName, // e.g., "2.80", "3.6", "4.2alpha"
								fullPath: `https://download.blender.org/release/${href}`,
								lastModified: null, // Date info is in a separate column, harder to parse
								links: links
							};
						}

						return null;
					});
					folderPromises.push(promise);
				}
			}
		});
		const folders = (await Promise.all(folderPromises)).filter((folder) => folder !== null);
		folders.sort((a, b) => compareVersions(b.version, a.version));
		blenderReleases.set(folders);
		return folders;
	} catch (error) {
		console.error('Error fetching Blender release list:', error);
		return [];
	}
}

/**
 * Fetches the minor versions (e.g., 5.0.0, 5.1.0) for a given major version folder URL,
 * along with their download URLs for the current platform and architecture.
 * @returns {Promise<FileLink[]>} List of minor versions with download URLs
 * @param {string} majorVersionFolderUrl
 * @param {string} currentPlatform
 * @param {string} currentArch
 */
async function getBlenderMinorVersionsWithDownload(
	majorVersionFolderUrl,
	currentPlatform,
	currentArch
) {
	try {
		// 1. Fetch the HTML of the version folder (e.g., Blender5.0/)
		const response = await fetch(majorVersionFolderUrl);
		const html = await response.text();

		// 2. Parse the HTML
		const parser = new DOMParser();
		const doc = parser.parseFromString(html, 'text/html');

		// 3. Map your platform/arch to the naming convention used in filenames
		/** @type {{ linux: string; windows: string; darwin: string; }} */
		const platformMap = {
			linux: 'linux',
			windows: 'windows',
			darwin: 'macos' // macOS is called 'darwin' in some contexts, but files use 'macos'
		};
		/** @type {{ x86_64: string; arm64: string; }} */
		const archMap = {
			x86_64: 'x64',
			arm64: 'arm64'
		};

		const targetPlatform =
			platformMap[/** @type {keyof platformMap} */ (currentPlatform)] || currentPlatform;
		const targetArch = archMap[/** @type {keyof archMap} */ (currentArch)] || currentArch;

		// 4. Get all file links and process them
		const links = doc.querySelectorAll('a');
		/** @type {Map<string, { [key: string]: { url: string; extension: string; platform: string; arch: string } }>} */
		const versionsMap = new Map(); // Key: version string, Value: object with files

		links.forEach((link) => {
			const href = link.getAttribute('href');
			if (!href) return;

			// Match pattern: blender-5.0.0-linux-x64.tar.xz
			// Regex captures: version, platform, arch, extension
			const match = href.match(/^blender-([\d.]+)-([a-z]+)-([a-z0-9]+)\.([a-z.]+)$/);
			if (match) {
				const [_, version, platform, arch, ext] =
					/** @type {[string, string, string, string, string]} */ (match);

				// Ignore checksum files (.md5, .sha256) if you don't need them
				if (ext === 'md5' || ext === 'sha256') return;

				// Store file info grouped by version
				if (!versionsMap.has(version)) {
					versionsMap.set(version, {});
				}
				const versionFiles = versionsMap.get(version);
				if (!versionFiles) return;
				const key = `${platform}-${arch}`;
				versionFiles[key] = {
					url: new URL(href, majorVersionFolderUrl).href,
					extension: ext,
					platform,
					arch
				};
			}
		});

		// 5. For each version, pick the correct download link based on target platform/arch
		const results = [];
		const targetKey = `${targetPlatform}-${targetArch}`;

		for (const [version, files] of versionsMap.entries()) {
			const fileInfo = files[targetKey];
			if (fileInfo) {
				results.push({
					version: version,
					downloadUrl: fileInfo.url,
					platform: targetPlatform,
					architecture: targetArch,
					fileExtension: fileInfo.extension,
					status: 'pending',
					percent: 0
				});
			} else {
				console.warn(`No matching file found for ${version} with ${targetKey}`);
			}
		}

		return results.sort((a, b) => compareVersions(a.version, b.version)); // Optional: sort versions
	} catch (error) {
		console.error('Error fetching Blender versions:', error);
		return [];
	}
}
// Helper function to compare version strings (e.g., "5.0.0", "5.0.1")
/**
 * @param {string} v1
 * @param {string} v2
 */
function compareVersions(v1, v2) {
	const parts1 = v1.split('.').map(Number);
	const parts2 = v2.split('.').map(Number);
	for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
		const num1 = parts1[i] || 0;
		const num2 = parts2[i] || 0;
		if (num1 !== num2) return num1 - num2;
	}
	return 0;
}
