/**
 * Plausibilitätsprüfung von ISBN-10, ISBN-13, ISSN, Handle, DOI und URN
 */

/**
 * Prüft eine ISBN-10 auf Plausibilität
 * @param {string} isbn10 - Die zu prüfende ISBN-10
 * @returns {boolean} - true wenn gültig, false wenn ungültig
 */
function validateISBN10(isbn10) {
    if (!isbn10) return false;
    
    // Normalisierung: Bindestriche und Leerzeichen entfernen
    const clean = isbn10.replace(/[-\s]/g, '');
    
    // Muss genau 10 Zeichen haben
    if (clean.length !== 10) return false;
    
    // Erste 9 Zeichen müssen Ziffern sein, letztes Zeichen Ziffer oder X
    if (!/^\d{9}[\dX]$/.test(clean)) return false;
    
    // Prüfziffer berechnen
    let sum = 0;
    for (let i = 0; i < 9; i++) {
        sum += parseInt(clean[i]) * (10 - i);
    }
    
    const checkDigit = clean[9];
    const calculatedCheck = (11 - (sum % 11)) % 11;
    
    return (calculatedCheck === 10 && checkDigit === 'X') || 
           (calculatedCheck < 10 && checkDigit === calculatedCheck.toString());
}

/**
 * Prüft eine ISBN-13 auf Plausibilität
 * @param {string} isbn13 - Die zu prüfende ISBN-13
 * @returns {boolean} - true wenn gültig, false wenn ungültig
 */
function validateISBN13(isbn13) {
    if (!isbn13) return false;
    
    // Normalisierung: Bindestriche und Leerzeichen entfernen
    const clean = isbn13.replace(/[-\s]/g, '');
    
    // Muss genau 13 Ziffern haben
    if (clean.length !== 13 || !/^\d{13}$/.test(clean)) return false;
    
    // Muss mit 978 oder 979 beginnen
    if (!clean.startsWith('978') && !clean.startsWith('979')) return false;
    
    // Prüfziffer berechnen (modulo 10)
    let sum = 0;
    for (let i = 0; i < 12; i++) {
        sum += parseInt(clean[i]) * (i % 2 === 0 ? 1 : 3);
    }
    
    const checkDigit = parseInt(clean[12]);
    const calculatedCheck = (10 - (sum % 10)) % 10;
    
    return checkDigit === calculatedCheck;
}

/**
 * Prüft einen DOI auf Plausibilität
 * @param {string} doi - Der zu prüfende DOI
 * @returns {boolean} - true wenn gültig, false wenn ungültig
 */
function validateDOI(doi) {
    if (!doi) return false;
    
    // DOI kann mit oder ohne "doi:" Präfix sein
    const clean = doi.replace(/^doi:\s*/i, '');
    
    // Grundlegendes DOI-Format: 10.xxxx/yyyy
    // Registrant Code muss mit 10. beginnen
    const doiRegex = /^10\.\d{4,}\/[^\s]+$/;
    
    if (!doiRegex.test(clean)) return false;
    
    // Weitere Plausibilitätsprüfungen
    const parts = clean.split('/');
    if (parts.length < 2) return false;
    
    const prefix = parts[0];
    const suffix = parts.slice(1).join('/');
    
    // Präfix muss 10.xxxx Format haben (mindestens 4 Ziffern nach 10.)
    if (!/^10\.\d{4,}$/.test(prefix)) return false;
    
    // Suffix darf nicht leer sein und keine Leerzeichen enthalten
    if (!suffix.trim() || /\s/.test(suffix)) return false;
    
    return true;
}

/**
 * Prüft eine URN auf Plausibilität
 * @param {string} urn - Die zu prüfende URN
 * @returns {boolean} - true wenn gültig, false wenn ungültig
 */
function validateURN(urn) {
    if (!urn) return false;
    
    // URN muss mit "urn:" beginnen (case-insensitive)
    if (!urn.toLowerCase().startsWith('urn:')) return false;
    
    // Grundlegendes URN-Format: urn:namespace:identifier
    const parts = urn.split(':');
    if (parts.length < 3) return false;
    
    const namespace = parts[1];
    const identifier = parts.slice(2).join(':');
    
    // Namespace-Validierung
    if (!namespace || !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(namespace)) {
        return false;
    }
    
    // Namespace darf nicht länger als 32 Zeichen sein
    if (namespace.length > 32) return false;
    
    // Identifier darf nicht leer sein
    if (!identifier) return false;
    
    // Prüfung auf reservierte Zeichen (vereinfacht)
    const reservedChars = /[<>"{}|\\^`\[\]]/;
    if (reservedChars.test(identifier)) return false;
    
    return true;
}

/**
 * Prüft eine ISSN auf Plausibilität
 * @param {string} issn - Die zu prüfende ISSN
 * @returns {boolean} - true wenn gültig, false wenn ungültig
 */
function validateISSN(issn) {
    if (!issn) return false;
    
    // Normalisierung: Bindestriche und Leerzeichen entfernen
    const clean = issn.replace(/[-\s]/g, '');
    
    // Muss genau 8 Zeichen haben
    if (clean.length !== 8) return false;
    
    // Erste 7 Zeichen müssen Ziffern sein, letztes Zeichen Ziffer oder X
    if (!/^\d{7}[\dX]$/.test(clean)) return false;
    
    // Prüfziffer berechnen (modulo 11)
    let sum = 0;
    for (let i = 0; i < 7; i++) {
        sum += parseInt(clean[i]) * (8 - i);
    }
    
    const checkDigit = clean[7];
    const calculatedCheck = (11 - (sum % 11)) % 11;
    
    return (calculatedCheck === 10 && checkDigit === 'X') || 
           (calculatedCheck < 10 && checkDigit === calculatedCheck.toString());
}

/**
 * Prüft eine eISSN (elektronische ISSN) auf Plausibilität
 * @param {string} eissn - Die zu prüfende eISSN
 * @returns {boolean} - true wenn gültig, false wenn ungültig
 */
function validateEISSN(eissn) {
    // eISSN hat das gleiche Format wie ISSN
    return validateISSN(eissn);
}

/**
 * Validierung verschiedener Identifier-Typen
 * @param {string} identifier - Der zu prüfende Identifier
 * @param {string} identifierType - Identifier Typ ("ISBN" | "ISSN" | "URN" | "DOI" | "Handle") 
 * @returns {object} - Objekt mit Typ und Validierungsergebnis
 */
function validateIdentifier(identifier, identifierType) {

	if (!identifier) {
	        return { type: 'unknown', valid: false, error: 'Leerer Identifier' };
	}

	const clean = identifier.trim();

	switch (identifierType)  {
		case "URN": return {
			            type: 'URN',
            			    valid: validateURN(clean),
            			    identifier: clean
        		    };
		case "DOI": if (clean.toLowerCase().startsWith('doi:') || clean.startsWith('10.')) {
			        return {
            				type: 'DOI',
            				valid: validateDOI(clean),
            				identifier: clean
        			};
    			    }
		case "ISBN": const isbnClean = clean.replace(/[-\s]/g, '');
   			     if (/^\d{10}$/.test(isbnClean) || /^\d{9}X$/.test(isbnClean)) {
        			return 	{
            				type: 'ISBN-10',
            				valid: validateISBN10(clean),
            				identifier: clean
        		    	    	};
    			     }
    	
			     if (/^\d{13}$/.test(isbnClean)) {
        			return {
            				type: 'ISBN-13',
            				valid: validateISBN13(clean),
            				identifier: clean
        			};
    			    }
		case "ISSN": const issnClean = clean.replace(/[-\s]/g, '');
   			     if (/^\d{8}$/.test(issnClean) || /^\d{7}X$/.test(issnClean)) {
        			return {
            				type: 'ISSN',
            				valid: validateISSN(clean),
            				identifier: clean
        			};
    			     } 
		case "Handle":if (clean.toLowerCase().startsWith('hdl:') || 
        			clean.toLowerCase().includes('hdl.handle.net') || 
        			clean.toLowerCase().includes('handle.net') ||
        				/^\d+(\.\d+)*\//.test(clean)) {
        			return {
            				type: 'Handle',
            				valid: validateHandle(clean),
            				identifier: clean
        			};
    			      }

	default:    return { type: 'Identifikator unbekannt: Struktur ist kein DOI, keine URN, ISBN, ISSN oder Handle', valid: false, error: 'Bitte prüfen Sie den gewählten Identifikator und dessen Inhalt (z.B DOI: 10.1515/zfsoz-2025-2017, URN: urn:nbn:de:0035-vetrepository-783215)' };
	}

}

/**
 * Hilfsfunktion: Normalisiert ISBN-Eingaben
 * @param {string} isbn - ISBN mit oder ohne Trennzeichen
 * @returns {string} - Normalisierte ISBN ohne Trennzeichen
 */
function normalizeISBN(isbn) {
    return isbn ? isbn.replace(/[-\s]/g, '') : '';
}

/**
 * Hilfsfunktion: Extrahiert DOI ohne Präfix
 * @param {string} doi - DOI mit oder ohne "doi:" Präfix
 * @returns {string} - DOI ohne Präfix
 */
function normalizeDOI(doi) {
    return doi ? doi.replace(/^doi:\s*/i, '') : '';
}

/**
 * Batch-Validierung für mehrere Identifier
 * @param {string[]} identifiers - Array von zu prüfenden Identifiern
 * @returns {object[]} - Array von Validierungsergebnissen
 */
function validateMultipleIdentifiers(identifiers) {
    if (!Array.isArray(identifiers)) {
        return [];
    }
    
    return identifiers.map(id => validateIdentifier(id));
}

/**
 * Prüft ob ein String eine gültige ISBN (10 oder 13) ist
 * @param {string} isbn - Zu prüfende ISBN
 * @returns {boolean} - true wenn gültige ISBN-10 oder ISBN-13
 */
function isValidISBN(isbn) {
    return validateISBN10(isbn) || validateISBN13(isbn);
}


function validateHandle(handle) {
    if (!handle) return false;

    // Handle kann mit oder ohne "hdl:" Präfix oder "http://hdl.handle.net/" sein
    let clean = handle.trim();

    // Verschiedene Handle-Präfixe entfernen
    clean = clean.replace(/^hdl:\s*/i, '');
    clean = clean.replace(/^https?:\/\/hdl\.handle\.net\//, '');
    clean = clean.replace(/^https?:\/\/handle\.net\//, '');

    // Handle-Format: prefix/suffix (z.B. 10.1000/123 oder 1721.1/12345)
    if (!clean.includes('/')) return false;

    const parts = clean.split('/');
    if (parts.length < 2) return false;

    const prefix = parts[0];
    const suffix = parts.slice(1).join('/');

    // Prefix-Validierung
    if (!prefix || prefix.length === 0) return false;

    // Prefix darf nur Zahlen, Punkte und Bindestriche enthalten
    if (!/^[0-9.-]+$/.test(prefix)) return false;

    // Suffix-Validierung
    if (!suffix || suffix.length === 0) return false;

    // Suffix darf keine Leerzeichen enthalten
    if (/\s/.test(suffix)) return false;

    // Reservierte Zeichen prüfen
    const reservedChars = /[<>"{}|\\^`\[\]]/;
    if (reservedChars.test(suffix)) return false;

    return true;
}


// ========================================
// Beispiele für die Verwendung
// ========================================

/* console.log('=== ISBN-10 Tests ===');
console.log('0-306-40615-2:', validateISBN10('0-306-40615-2')); // true
console.log('0306406152:', validateISBN10('0306406152')); // true
console.log('0306406151:', validateISBN10('0306406151')); // false
console.log('0-19-852663-6:', validateISBN10('0-19-852663-6')); // true

console.log('\n=== ISBN-13 Tests ===');
console.log('978-0-306-40615-7:', validateISBN13('978-0-306-40615-7')); // true
console.log('9780306406157:', validateISBN13('9780306406157')); // true
console.log('9780306406156:', validateISBN13('9780306406156')); // false
console.log('979-0-000-00000-0:', validateISBN13('979-0-000-00000-0')); // true

console.log('\n=== DOI Tests ===');
console.log('10.1000/182:', validateDOI('10.1000/182')); // true
console.log('doi:10.1000/182:', validateDOI('doi:10.1000/182')); // true
console.log('10.1038/nature12373:', validateDOI('10.1038/nature12373')); // true
console.log('10.123/456:', validateDOI('10.123/456')); // false (zu kurz)

console.log('\n=== URN Tests ===');
console.log('urn:isbn:0451450523:', validateURN('urn:isbn:0451450523')); // true
console.log('urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66:', validateURN('urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66')); // true
console.log('urn:nbn:de:bvb:19-146642:', validateURN('urn:nbn:de:bvb:19-146642')); // true
console.log('not-a-urn:', validateURN('not-a-urn')); // false


console.log('\n=== Hilfsfunktionen ===');
console.log('Normalisierte ISBN:', normalizeISBN('978-0-306-40615-7'));
console.log('Normalisierter DOI:', normalizeDOI('doi:10.1000/182'));
console.log('Gültige ISBN?:', isValidISBN('978-0-306-40615-7'));

*/
