/**
 * Validator for parsed TrueRef config objects (TRUEREF-0013).
 *
 * Produces descriptive, field-scoped error messages so callers can surface
 * exactly what is wrong with a user-supplied config file.
 */

import type { TrueRefConfig } from '$lib/types';
import { CONFIG_CONSTRAINTS } from './trueref-config.schema.js';

// ---------------------------------------------------------------------------
// Validation result types
// ---------------------------------------------------------------------------

export interface ValidationResult {
	valid: boolean;
	errors: string[];
	warnings: string[];
}

// ---------------------------------------------------------------------------
// Public validator
// ---------------------------------------------------------------------------

/**
 * Validate a parsed `TrueRefConfig` object against all constraint rules.
 *
 * Returns a `ValidationResult` instead of throwing so callers can decide
 * whether to abort or just surface warnings.
 *
 * @param config - The already-parsed (but not yet validated) config object.
 */
export function validateConfig(config: TrueRefConfig): ValidationResult {
	const errors: string[] = [];
	const warnings: string[] = [];

	// ---- projectTitle -------------------------------------------------------
	if (config.projectTitle !== undefined) {
		const { minLength, maxLength } = CONFIG_CONSTRAINTS.projectTitle;
		if (config.projectTitle.length < minLength) {
			errors.push(`projectTitle must be at least ${minLength} character(s) long`);
		}
		if (config.projectTitle.length > maxLength) {
			warnings.push(`projectTitle exceeds ${maxLength} characters and was truncated`);
		}
	}

	// ---- description --------------------------------------------------------
	if (config.description !== undefined) {
		const { minLength, maxLength } = CONFIG_CONSTRAINTS.description;
		if (config.description.length < minLength) {
			errors.push(`description must be at least ${minLength} characters long`);
		}
		if (config.description.length > maxLength) {
			warnings.push(`description exceeds ${maxLength} characters and was truncated`);
		}
	}

	// ---- folders ------------------------------------------------------------
	if (config.folders !== undefined) {
		const { maxItems, maxLength } = CONFIG_CONSTRAINTS.folders;
		if (config.folders.length > maxItems) {
			warnings.push(`folders has more than ${maxItems} entries; extras were dropped`);
		}
		for (const [i, entry] of config.folders.entries()) {
			if (entry.length > maxLength) {
				warnings.push(`folders[${i}] exceeds ${maxLength} characters: "${entry.slice(0, 40)}..."`);
			}
		}
	}

	// ---- excludeFolders -----------------------------------------------------
	if (config.excludeFolders !== undefined) {
		const { maxItems, maxLength } = CONFIG_CONSTRAINTS.excludeFolders;
		if (config.excludeFolders.length > maxItems) {
			warnings.push(`excludeFolders has more than ${maxItems} entries; extras were dropped`);
		}
		for (const [i, entry] of config.excludeFolders.entries()) {
			if (entry.length > maxLength) {
				warnings.push(
					`excludeFolders[${i}] exceeds ${maxLength} characters: "${entry.slice(0, 40)}..."`
				);
			}
		}
	}

	// ---- excludeFiles -------------------------------------------------------
	if (config.excludeFiles !== undefined) {
		const { maxItems, maxLength } = CONFIG_CONSTRAINTS.excludeFiles;
		if (config.excludeFiles.length > maxItems) {
			warnings.push(`excludeFiles has more than ${maxItems} entries; extras were dropped`);
		}
		for (const [i, entry] of config.excludeFiles.entries()) {
			if (entry.length > maxLength) {
				warnings.push(
					`excludeFiles[${i}] exceeds ${maxLength} characters: "${entry.slice(0, 40)}..."`
				);
			}
			// Exact filenames must not contain path separators.
			if (entry.includes('/') || entry.includes('\\')) {
				errors.push(
					`excludeFiles[${i}] must be a plain filename without path separators: "${entry}"`
				);
			}
		}
	}

	// ---- rules --------------------------------------------------------------
	if (config.rules !== undefined) {
		const { maxItems, minLength, maxLength } = CONFIG_CONSTRAINTS.rules;
		if (config.rules.length > maxItems) {
			warnings.push(`rules has more than ${maxItems} entries; extras were dropped`);
		}
		for (const [i, rule] of config.rules.entries()) {
			if (rule.length < minLength) {
				errors.push(`rules[${i}] must be at least ${minLength} characters long`);
			}
			if (rule.length > maxLength) {
				warnings.push(`rules[${i}] exceeds ${maxLength} characters and was truncated`);
			}
		}
	}

	// ---- previousVersions ---------------------------------------------------
	if (config.previousVersions !== undefined) {
		const { maxItems } = CONFIG_CONSTRAINTS.previousVersions;
		const { pattern } = CONFIG_CONSTRAINTS.versionTag;

		if (config.previousVersions.length > maxItems) {
			warnings.push(`previousVersions has more than ${maxItems} entries; extras were dropped`);
		}

		for (const [i, version] of config.previousVersions.entries()) {
			if (!pattern.test(version.tag)) {
				errors.push(
					`previousVersions[${i}].tag "${version.tag}" does not match the expected pattern ` +
						`(e.g. "v1.2.3", "1.2", "v2.0.0-beta.1")`
				);
			}
			if (!version.title || version.title.trim().length === 0) {
				errors.push(`previousVersions[${i}].title must be a non-empty string`);
			}
		}
	}

	return {
		valid: errors.length === 0,
		errors,
		warnings
	};
}
