import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const pdfParse = require('pdf-parse/lib/pdf-parse.js');
import { Op } from 'sequelize';
import Match from '../models/Match.js';
import Team from '../models/Team.js';
import ClubTeam from '../models/ClubTeam.js';
import League from '../models/League.js';
import Location from '../models/Location.js';
import { devLog } from '../utils/logger.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

class PDFParserService {
    /**
     * Parst eine PDF-Datei und extrahiert Spiel-Daten
     * @param {string} filePath - Pfad zur PDF-Datei
     * @param {number} clubId - ID des Vereins
     * @returns {Promise<Object>} Geparste Spiel-Daten
     */
    static async parsePDF(filePath, clubId) {
        try {

            if (!fs.existsSync(filePath)) {
                throw new Error('PDF-Datei nicht gefunden');
            }

            // Bestimme Dateityp basierend auf Dateiendung
            const fileExtension = path.extname(filePath).toLowerCase();
            let fileContent;
            let extractedLines = null;
            let lineEntries = null;

            if (fileExtension === '.pdf') {
                try {
                    const { text, lines, entries } = await this.extractPdfTextWithLayout(filePath);
                    fileContent = text;
                    extractedLines = lines;
                    lineEntries = entries;
                } catch (layoutError) {
                    console.error('[PDFParserService.parsePDF] - Layout extraction failed, falling back to pdf-parse:', layoutError);
                    const pdfBuffer = fs.readFileSync(filePath);
                    const pdfData = await pdfParse(pdfBuffer);
                    fileContent = pdfData.text;
                }
            } else {
                // Fallback für TXT-Dateien (für Tests)
                fileContent = fs.readFileSync(filePath, 'utf8');
            }

            // Parse den Text nach Spiel-Daten
            const parsedData = this.extractMatchData(fileContent, clubId, extractedLines, lineEntries);
            
            
            return parsedData;
        } catch (error) {
            console.error('[PDFParserService.parsePDF] - Error:', error);
            throw error;
        }
    }

    /**
     * Extrahiert Spiel-Daten aus dem PDF-Text
     * @param {string} text - Der extrahierte Text aus der PDF
     * @param {number} clubId - ID des Vereins
     * @returns {Object} Geparste Daten mit Matches und Metadaten
     */
    static extractMatchData(text, clubId, providedLines = null, providedLineEntries = null) {
        const matches = [];
        const errors = [];
        const metadata = {
            totalLines: 0,
            parsedMatches: 0,
            errors: 0
        };

        try {
            // Teile Text in Zeilen auf
            const linesSource = providedLines && Array.isArray(providedLines) ? providedLines : text.split('\n');
            const lines = [];
            const filteredLineEntries = [];

            linesSource.forEach((line, idx) => {
                const trimmed = typeof line === 'string' ? line.trim() : '';
                if (trimmed.length > 0) {
                    lines.push(trimmed);
                    if (providedLineEntries && Array.isArray(providedLineEntries) && providedLineEntries[idx]) {
                        filteredLineEntries.push(providedLineEntries[idx]);
                    }
                }
            });
            metadata.totalLines = lines.length;


            // Verschiedene Parsing-Strategien je nach PDF-Format
            const strategies = [
                { name: 'Standard Format', fn: (lns, club, entries) => PDFParserService.parseStandardFormat(lns, club, entries) },
                { name: 'Table Format', fn: (lns, club, entries) => PDFParserService.parseTableFormat(lns, club, entries) },
                { name: 'List Format', fn: (lns, club, entries) => PDFParserService.parseListFormat(lns, club, entries) }
            ];

            
            for (const strategy of strategies) {
                try {
                    const result = strategy.fn(lines, clubId, filteredLineEntries.length === lines.length ? filteredLineEntries : null);
                    
                    if (result.matches.length > 0) {
                        matches.push(...result.matches);
                        metadata.parsedMatches += result.matches.length;
                        break; // Erste erfolgreiche Strategie verwenden
                    }
                } catch (strategyError) {
                    errors.push(`Strategy ${strategy.name} failed: ${strategyError.message}`);
                }
            }

            metadata.errors = errors.length;

            return {
                matches,
                errors,
                metadata,
                rawText: text.substring(0, 1000), // Erste 1000 Zeichen für Debugging
                allLines: lines, // Alle Zeilen für Debugging
                debugInfo: {
                    totalTextLength: text.length,
                    totalLines: lines.length,
                    firstFewLines: lines.slice(0, 10),
                    lastFewLines: lines.slice(-5)
                }
            };
        } catch (error) {
            console.error('[PDFParserService.extractMatchData] - Error:', error);
            throw error;
        }
    }

    /**
     * Standard-Format Parser (Datum, Zeit, Heimteam, Gastteam, Code, Pins)
     * @param {Array} lines - Textzeilen
     * @param {number} clubId - ID des Vereins
     * @returns {Object} Geparste Matches
     */
    static parseStandardFormat(lines, clubId, lineEntries = null) {
        const matches = [];
        
        
        for (let i = 0; i < lines.length; i++) {
            const line = lines[i];
            const lineDetail = Array.isArray(lineEntries) ? lineEntries[i] : null;
            const columnSegments = lineDetail ? this.segmentLineByPositions(lineDetail) : null;
            let homeFromColumns = null;
            let guestFromColumns = null;
            let codeFromColumns = null;

            if (columnSegments && columnSegments.length >= 3) {
                homeFromColumns = columnSegments[1]?.trim() || null;
                guestFromColumns = columnSegments[2]?.trim() || null;
                const lastSegment = columnSegments[columnSegments.length - 1];
                if (lastSegment) {
                    const candidateCode = lastSegment.replace(/\s+/g, '').trim();
                    if (/^[A-Z0-9]{12}$/.test(candidateCode)) {
                        codeFromColumns = candidateCode;
                    }
                }
            }
            
            // Suche nach Datum-Pattern (dd.mm.yyyy oder dd/mm/yyyy)
            const dateMatch = line.match(/(\d{1,2})[./](\d{1,2})[./](\d{4})/);
            if (dateMatch) {
                
                // Debug: Zeige die gesamte Zeile mit sichtbaren Whitespaces
                const debugLine = line.replace(/\s/g, (match) => {
                    if (match === ' ') return '·'; // Mittelpunkt für normales Leerzeichen
                    if (match === '\t') return '→'; // Pfeil für Tab
                    if (match === '\n') return '↵'; // Enter-Zeichen
                    if (match === '\r') return '⏎'; // Carriage Return
                    return `[${match.charCodeAt(0)}]`; // Zeichencode für andere Whitespaces
                });
                
                try {
                    const [, day, month, year] = dateMatch;
                    const date = new Date(`${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`);
                    
                    // Suche nach Zeit-Pattern (hh:mm) - kann direkt nach Datum oder mit Leerzeichen sein
                    const timeMatch = line.match(/(\d{1,2}):(\d{2})/);
                    let time = null;
                    if (timeMatch) {
                        time = `${timeMatch[1].padStart(2, '0')}:${timeMatch[2]}`;
                    }
                    
                    
                    // Entferne Datum (mit optionalem Wochentag) und Zeit vom Anfang der Zeile
                    // Format: "Sa. 06.09.2025 10:00" oder "06.09.2025 10:00"
                    const cleanLine = line
                        .replace(/^[A-Za-z]{2,3}\.\s*/, '') // Entferne Wochentag (z.B. "Sa. ", "Mo. ", "Fre. ")
                        .replace(/^\d{1,2}[./]\d{1,2}[./]\d{4}/, '') // Entferne Datum
                        .replace(/^\s*\d{1,2}:\d{2}/, '') // Entferne Zeit
                        .trim();
                    
                    // Entferne Nummerierung am Anfang (z.B. "(1)")
                    const cleanLine2 = cleanLine.replace(/^\(\d+\)/, '');
                    
                    // Entferne alle Inhalte in Klammern (z.B. "(J11)")
                    const cleanLine3 = cleanLine2.replace(/\([^)]*\)/g, '');
                    
                    // Suche nach Code (12 Zeichen) oder PIN (4 Ziffern) am Ende
                    let codeMatch = cleanLine3.match(/([A-Z0-9]{12})$/);
                    const pinMatch = cleanLine3.match(/(\d{4})$/);
                    
                    let code = null;
                    let homePin = null;
                    let guestPin = null;
                    let teamsPart = cleanLine3;
                    
                    if (codeMatch) {
                        // Code gefunden (12 Zeichen)
                        code = codeMatch[1];
                        teamsPart = cleanLine3.substring(0, cleanLine3.length - code.length).trim();
                    } else if (pinMatch) {
                        // PIN gefunden (4 Ziffern)
                        const pin = pinMatch[1];
                        teamsPart = cleanLine3.substring(0, cleanLine3.length - pin.length).trim();
                        
                        // Die PIN gehört immer zu "Harheimer TC"
                        // Prüfe, ob "Harheimer TC" am Anfang oder am Ende steht
                        const harheimerIndex = teamsPart.indexOf('Harheimer TC');
                        
                        if (harheimerIndex >= 0) {
                            // "Harheimer TC" gefunden
                            let beforeHarheimer = teamsPart.substring(0, harheimerIndex).trim();
                            
                            // Entferne führende Spielnummer (z.B. "1", "2", etc.)
                            beforeHarheimer = beforeHarheimer.replace(/^\d+/, '').trim();
                            
                            if (beforeHarheimer && beforeHarheimer.length > 0) {
                                // Es gibt einen Team-Namen vor "Harheimer TC" → Harheimer ist Gastteam → guestPin
                                guestPin = pin;
                            } else {
                                // "Harheimer TC" steht am Anfang (nur Spielnummer davor) → Harheimer ist Heimteam → homePin
                                homePin = pin;
                            }
                        } else {
                            // "Harheimer TC" nicht gefunden → Standardlogik: PIN gehört zum Gastteam
                            guestPin = pin;
                        }
                    }
                    
                    if (!code && codeFromColumns) {
                        code = codeFromColumns;
                        teamsPart = teamsPart.replace(new RegExp(`${code}$`), '').trim();
                    }

                    if (code || pinMatch) {
                        
                        
                        // Debug: Zeige Whitespaces als lesbare Zeichen
                        const debugTeamsPart = teamsPart.replace(/\s/g, (match) => {
                            if (match === ' ') return '·'; // Mittelpunkt für normales Leerzeichen
                            if (match === '\t') return '→'; // Pfeil für Tab
                            return `[${match.charCodeAt(0)}]`; // Zeichencode für andere Whitespaces
                        });
                        
                        // Neue Strategie: Teile die Zeile durch mehrere Leerzeichen (wie in der Tabelle)
                        // Die Struktur ist: Heimmannschaft    Gastmannschaft    Code
                        const parts = teamsPart.split(/\s{2,}/); // Mindestens 2 Leerzeichen als Trenner
                        
                        
                        let homeTeamName = '';
                        let guestTeamName = '';
                        
                        if (parts.length >= 2) {
                            homeTeamName = parts[0].trim();
                            guestTeamName = parts[1].trim();
                            
                            // Entferne noch verbleibende Klammern aus den Team-Namen
                            homeTeamName = homeTeamName.replace(/\([^)]*\)/g, '').trim();
                            guestTeamName = guestTeamName.replace(/\([^)]*\)/g, '').trim();
                            
                            
                            // Erkenne römische Ziffern am Ende der Team-Namen
                            // Römische Ziffern: I, II, III, IV, V, VI, VII, VIII, IX, X, XI, XII, etc.
                            const romanNumeralPattern = /\s+(I{1,3}|IV|V|VI{0,3}|IX|X|XI{0,2})$/;
                            
                            // Prüfe Heimteam auf römische Ziffern
                            const homeRomanMatch = homeTeamName.match(romanNumeralPattern);
                            if (homeRomanMatch) {
                                const romanNumeral = homeRomanMatch[1];
                                const baseName = homeTeamName.replace(romanNumeralPattern, '').trim();
                                homeTeamName = `${baseName} ${romanNumeral}`;
                            }
                            
                            // Prüfe Gastteam auf römische Ziffern
                            const guestRomanMatch = guestTeamName.match(romanNumeralPattern);
                            if (guestRomanMatch) {
                                const romanNumeral = guestRomanMatch[1];
                                const baseName = guestTeamName.replace(romanNumeralPattern, '').trim();
                                guestTeamName = `${baseName} ${romanNumeral}`;
                            }
                            
                        } else {
                            // Fallback: Versuche mit einzelnen Leerzeichen zu trennen
                            
                            // Strategie 1: Suche nach "Harheimer TC" als Heimteam oder Gastteam
                            if (teamsPart.includes('Harheimer TC')) {
                                const harheimerIndex = teamsPart.indexOf('Harheimer TC');
                                let beforeHarheimer = teamsPart.substring(0, harheimerIndex).trim();
                                let afterHarheimer = teamsPart.substring(harheimerIndex + 'Harheimer TC'.length).trim();
                                
                                beforeHarheimer = beforeHarheimer
                                    .replace(/^\(\d+\)/, '')
                                    .replace(/^\d+/, '')
                                    .trim();
                                afterHarheimer = afterHarheimer
                                    .replace(/^\(\d+\)/, '')
                                    .replace(/^\d+/, '')
                                    .trim();
                                
                                const romanNumeralCandidates = ['XII', 'XI', 'X', 'IX', 'VIII', 'VII', 'VI', 'V', 'IV', 'III', 'II', 'I'];

                                const matchLeadingRoman = (token) => {
                                    if (!token) {
                                        return null;
                                    }
                                    const normalizedToken = token.trim();
                                    for (const candidate of romanNumeralCandidates) {
                                        if (normalizedToken.startsWith(candidate)) {
                                            const nextChar = normalizedToken.charAt(candidate.length);
                                            if (!nextChar || /\s|[A-ZÄÖÜẞ]/.test(nextChar)) {
                                                const remainder = normalizedToken.slice(candidate.length).trimStart();
                                                return { roman: candidate, remainder };
                                            }
                                        }
                                    }
                                    return null;
                                };

                                const extractLeadingRomanFromTokens = (tokenList) => {
                                    const tokensCopy = Array.isArray(tokenList) ? [...tokenList] : [];
                                    if (tokensCopy.length === 0) {
                                        return { roman: null, tokens: tokensCopy };
                                    }

                                    const firstToken = tokensCopy[0];
                                    const match = matchLeadingRoman(firstToken);

                                    if (match) {
                                        const { roman, remainder } = match;
                                        if (remainder) {
                                            tokensCopy[0] = remainder;
                                        } else {
                                            tokensCopy.shift();
                                        }
                                        return { roman, tokens: tokensCopy };
                                    }

                                    return { roman: null, tokens: tokensCopy };
                                };

                                if (!beforeHarheimer && afterHarheimer) {
                                    const tokens = afterHarheimer.split(/\s+/).filter(Boolean);
                                    const { roman: homeRoman, tokens: guestTokens } = extractLeadingRomanFromTokens(tokens);
                                    const homeSuffix = homeRoman ? ` ${homeRoman}` : '';
                                    homeTeamName = `Harheimer TC${homeSuffix}`;
                                    guestTeamName = guestTokens.join(' ').trim();
                                } else if (beforeHarheimer && !afterHarheimer) {
                                    // "Harheimer TC" ist Gastteam ohne weitere Tokens
                                    homeTeamName = beforeHarheimer.replace(/\([^)]*\)/g, '').trim();
                                    guestTeamName = 'Harheimer TC';
                                } else if (beforeHarheimer && afterHarheimer) {
                                    // "Harheimer TC" steht in der Mitte → Harheimer ist Gast, Tokens nach Harheimer gehören zu ihm
                                    homeTeamName = beforeHarheimer.replace(/\([^)]*\)/g, '').trim();
                                    const tokens = afterHarheimer.split(/\s+/).filter(Boolean);
                                    const { roman: guestRoman, tokens: remainingTokens } = extractLeadingRomanFromTokens(tokens);
                                    const guestSuffix = guestRoman ? ` ${guestRoman}` : '';
                                    guestTeamName = `Harheimer TC${guestSuffix}`;
                                    if (remainingTokens.length > 0) {
                                        const trailingText = remainingTokens.join(' ').trim();
                                        if (trailingText) {
                                            guestTeamName = `${guestTeamName} ${trailingText}`.trim();
                                        }
                                    }
                                } else {
                                    // Nur "Harheimer TC" ohne weitere Kontexte → überspringen
                                    continue;
                                }

                                homeTeamName = homeTeamName.replace(/\([^)]*\)/g, '').trim();
                                guestTeamName = guestTeamName.replace(/\([^)]*\)/g, '').trim();
                            } else {
                                // Strategie 2: Suche nach Großbuchstaben am Anfang des zweiten Teams
                                const teamSplitMatch = teamsPart.match(/^([A-Za-z0-9\s\-\.]+?)\s+([A-Z][A-Za-z0-9\s\-\.]+)$/);
                                
                                if (teamSplitMatch) {
                                    homeTeamName = teamSplitMatch[1].trim();
                                    guestTeamName = teamSplitMatch[2].trim();
                                    
                                } else {
                                    continue;
                                }
                            }
                        }
                        
                        if (homeFromColumns) {
                            homeTeamName = homeFromColumns;
                        }
                        if (guestFromColumns) {
                            guestTeamName = guestFromColumns;
                        }

                        if (homeTeamName && guestTeamName) {
                            
                            matches.push({
                                date: date,
                                time: time,
                                homeTeamName: homeTeamName,
                                guestTeamName: guestTeamName,
                                code: code,
                                homePin: homePin,
                                guestPin: guestPin,
                                clubId: clubId,
                                rawLine: line
                            });
                        }
                    } else {
                    }
                } catch (parseError) {
                }
            }
        }
        
        return { matches };
    }

    static segmentLineByPositions(lineDetail) {
        if (!lineDetail || !Array.isArray(lineDetail.items)) {
            return null;
        }

        const intraWordGapThreshold = 1.5;
        const columnGapThreshold = 12;
        const segments = [];

        let currentSegment = '';
        let previousItem = null;

        lineDetail.items.forEach((item) => {
            if (!item || typeof item.text !== 'string') {
                return;
            }
            const text = item.text;
            if (!text || text.trim().length === 0) {
                return;
            }

            if (previousItem) {
                const previousEnd = previousItem.x + previousItem.width;
                const gap = item.x - previousEnd;

                if (gap > columnGapThreshold) {
                    if (currentSegment.trim().length > 0) {
                        segments.push(currentSegment.trim());
                    }
                    currentSegment = '';
                } else if (gap > intraWordGapThreshold) {
                    currentSegment += ' ';
                }
            }

            currentSegment += text;
            previousItem = item;
        });

        if (currentSegment.trim().length > 0) {
            segments.push(currentSegment.trim());
        }

        return segments.length > 0 ? segments : null;
    }
 
    /**
     * Tabellen-Format Parser
     * @param {Array} lines - Textzeilen
     * @param {number} clubId - ID des Vereins
     * @returns {Object} Geparste Matches
     */
    static parseTableFormat(lines, clubId, lineEntries = null) {
        const matches = [];
        
        // Suche nach Tabellen-Header
        let headerIndex = -1;
        for (let i = 0; i < lines.length; i++) {
            if (lines[i].toLowerCase().includes('datum') && 
                lines[i].toLowerCase().includes('zeit') && 
                lines[i].toLowerCase().includes('heim') && 
                lines[i].toLowerCase().includes('gast')) {
                headerIndex = i;
                break;
            }
        }
        
        if (headerIndex >= 0) {
            // Parse Tabellen-Zeilen
            for (let i = headerIndex + 1; i < lines.length; i++) {
                const line = lines[i];
                const columns = line.split(/\s{2,}|\t/); // Split bei mehreren Leerzeichen oder Tabs
                
                if (columns.length >= 4) {
                    try {
                        const dateStr = columns[0];
                        const timeStr = columns[1];
                        const homeTeam = columns[2];
                        const guestTeam = columns[3];
                        const code = columns[4] || null;
                        const homePin = columns[5] || null;
                        const guestPin = columns[6] || null;
                        
                        // Parse Datum
                        const dateMatch = dateStr.match(/(\d{1,2})[./](\d{1,2})[./](\d{4})/);
                        if (dateMatch) {
                            const [, day, month, year] = dateMatch;
                            const date = new Date(`${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`);
                            
                            matches.push({
                                date: date,
                                time: timeStr || null,
                                homeTeamName: homeTeam.trim(),
                                guestTeamName: guestTeam.trim(),
                                code: code ? code.trim() : null,
                                homePin: homePin ? homePin.trim() : null,
                                guestPin: guestPin ? guestPin.trim() : null,
                                clubId: clubId,
                                rawLine: line
                            });
                        }
                    } catch (parseError) {
                    }
                }
            }
        }
        
        return { matches };
    }

    /**
     * Listen-Format Parser
     * @param {Array} lines - Textzeilen
     * @param {number} clubId - ID des Vereins
     * @returns {Object} Geparste Matches
     */
    static parseListFormat(lines, clubId, lineEntries = null) {
        const matches = [];
        
        for (let i = 0; i < lines.length; i++) {
            const line = lines[i];
            
            // Suche nach Nummerierten Listen (1., 2., etc.)
            const listMatch = line.match(/^\d+\.\s*(.+)/);
            if (listMatch) {
                const content = listMatch[1];
                
                // Versuche verschiedene Formate zu parsen
                const patterns = [
                    /(\d{1,2}[./]\d{1,2}[./]\d{4})\s+(\d{1,2}:\d{2})?\s+(.+?)\s+vs?\s+(.+?)(?:\s+code[:\s]*([A-Za-z0-9]+))?(?:\s+home[:\s]*pin[:\s]*([A-Za-z0-9]+))?(?:\s+guest[:\s]*pin[:\s]*([A-Za-z0-9]+))?/i,
                    /(\d{1,2}[./]\d{1,2}[./]\d{4})\s+(\d{1,2}:\d{2})?\s+(.+?)\s+-\s+(.+?)(?:\s+code[:\s]*([A-Za-z0-9]+))?(?:\s+heim[:\s]*pin[:\s]*([A-Za-z0-9]+))?(?:\s+gast[:\s]*pin[:\s]*([A-Za-z0-9]+))?/i
                ];
                
                for (const pattern of patterns) {
                    const match = content.match(pattern);
                    if (match) {
                        try {
                            const [, dateStr, timeStr, homeTeam, guestTeam, code, homePin, guestPin] = match;
                            
                            // Parse Datum
                            const dateMatch = dateStr.match(/(\d{1,2})[./](\d{1,2})[./](\d{4})/);
                            if (dateMatch) {
                                const [, day, month, year] = dateMatch;
                                const date = new Date(`${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`);
                                
                                matches.push({
                                    date: date,
                                    time: timeStr || null,
                                    homeTeamName: homeTeam.trim(),
                                    guestTeamName: guestTeam.trim(),
                                    code: code ? code.trim() : null,
                                    homePin: homePin ? homePin.trim() : null,
                                    guestPin: guestPin ? guestPin.trim() : null,
                                    clubId: clubId,
                                    rawLine: line
                                });
                                break; // Erste erfolgreiche Pattern verwenden
                            }
                        } catch (parseError) {
                        }
                    }
                }
            }
        }
        
        return { matches };
    }

    /**
     * Speichert geparste Matches in der Datenbank
     * @param {Array} matches - Array von Match-Objekten
     * @param {number} leagueId - ID der Liga
     * @returns {Promise<Object>} Ergebnis der Speicherung
     */
    static async saveMatchesToDatabase(matches, leagueId) {
        try {

            const results = {
                created: 0,
                updated: 0,
                errors: []
            };

            for (const matchData of matches) {
                try {
                    let debugInfo;
                    if (matchData.code) {
                        debugInfo = `Code: ${matchData.code}`;
                    } else if (matchData.homePin && matchData.guestPin) {
                        debugInfo = `HomePin: ${matchData.homePin}, GuestPin: ${matchData.guestPin}`;
                    } else if (matchData.homePin) {
                        debugInfo = `HomePin: ${matchData.homePin}`;
                    } else if (matchData.guestPin) {
                        debugInfo = `GuestPin: ${matchData.guestPin}`;
                    }
                    
                    // Lade alle Matches für das Datum und die Liga
                    
                    // Konvertiere das Datum zu einem Datum ohne Zeit für den Vergleich
                    const dateOnly = new Date(matchData.date.getFullYear(), matchData.date.getMonth(), matchData.date.getDate());
                    const nextDay = new Date(dateOnly);
                    nextDay.setDate(nextDay.getDate() + 1);
                    
                    const existingMatches = await Match.findAll({
                        where: {
                            date: {
                                [Op.gte]: dateOnly,  // Größer oder gleich dem Datum
                                [Op.lt]: nextDay     // Kleiner als der nächste Tag
                            },
                            leagueId: leagueId,
                            ...(matchData.time && { time: matchData.time }) // Füge Zeit hinzu wenn vorhanden
                        },
                        include: [
                            {
                                model: Team,
                                as: 'homeTeam',
                                attributes: ['id', 'name']
                            },
                            {
                                model: Team,
                                as: 'guestTeam',
                                attributes: ['id', 'name']
                            }
                        ]
                    });
                    
                    
                    const timeFilter = matchData.time ? ` and time ${matchData.time}` : '';
                    
                    // Debug: Zeige alle gefundenen Matches und lade Teams manuell
                    for (let i = 0; i < existingMatches.length; i++) {
                        const match = existingMatches[i];
                        
                        // Lade Teams manuell
                        const homeTeam = await Team.findByPk(match.homeTeamId);
                        const guestTeam = await Team.findByPk(match.guestTeamId);
                        
                        
                        // Füge die Teams zum Match-Objekt hinzu
                        match.homeTeam = homeTeam;
                        match.guestTeam = guestTeam;
                    }
                    
                    // Suche nach dem passenden Match basierend auf Gastmannschaft
                    const matchingMatch = existingMatches.find(match => {
                        if (!match.guestTeam) return false;
                        
                        const guestTeamName = match.guestTeam.name;
                        const searchGuestName = matchData.guestTeamName;

                        return PDFParserService.namesRoughlyMatch(guestTeamName, searchGuestName);
                    });
                    
                    if (matchingMatch) {
                        
                        // Update das bestehende Match mit Code und Pins
                        // Erstelle Update-Objekt nur mit vorhandenen Feldern
                        const updateData = {};
                        if (matchData.code) {
                            updateData.code = matchData.code;
                        }
                        if (matchData.homePin) {
                            updateData.homePin = matchData.homePin;
                        }
                        if (matchData.guestPin) {
                            updateData.guestPin = matchData.guestPin;
                        }
                        
                        await matchingMatch.update(updateData);
                        results.updated++;
                        
                        let updateInfo;
                        if (matchData.code) {
                            updateInfo = `code: ${matchData.code}`;
                        } else if (matchData.homePin && matchData.guestPin) {
                            updateInfo = `homePin: ${matchData.homePin}, guestPin: ${matchData.guestPin}`;
                        } else if (matchData.homePin) {
                            updateInfo = `homePin: ${matchData.homePin}`;
                        } else if (matchData.guestPin) {
                            updateInfo = `guestPin: ${matchData.guestPin}`;
                        }
                        
                        // Lade das aktualisierte Match neu, um die aktuellen Werte zu zeigen
                        await matchingMatch.reload();
                        const currentValues = [];
                        if (matchingMatch.code) currentValues.push(`code: ${matchingMatch.code}`);
                        if (matchingMatch.homePin) currentValues.push(`homePin: ${matchingMatch.homePin}`);
                        if (matchingMatch.guestPin) currentValues.push(`guestPin: ${matchingMatch.guestPin}`);
                    } else {
                        
                        // Fallback: Versuche Teams direkt zu finden
                        let homeTeam = await Team.findOne({
                            where: { 
                                name: matchData.homeTeamName,
                                clubId: matchData.clubId
                            }
                        });

                        let guestTeam = await Team.findOne({
                            where: { 
                                name: matchData.guestTeamName,
                                clubId: matchData.clubId
                            }
                        });
                        
                        // If exact match failed, try fuzzy matching
                        if (!homeTeam || !guestTeam) {
                            const allTeams = await Team.findAll({
                                where: { clubId: matchData.clubId },
                                attributes: ['id', 'name']
                            });
                            
                            // Fuzzy-Matching für Team-Namen
                            if (!homeTeam) {
                                homeTeam = allTeams.find(t => 
                                    PDFParserService.namesRoughlyMatch(t.name, matchData.homeTeamName)
                                );
                            }
                            
                            if (!guestTeam) {
                                guestTeam = allTeams.find(t => 
                                    PDFParserService.namesRoughlyMatch(t.name, matchData.guestTeamName)
                                );
                            }
                        }

                        if (!homeTeam || !guestTeam) {
                            let errorInfo;
                            if (matchData.code) {
                                errorInfo = `Code: ${matchData.code}`;
                            } else if (matchData.homePin && matchData.guestPin) {
                                errorInfo = `HomePin: ${matchData.homePin}, GuestPin: ${matchData.guestPin}`;
                            } else if (matchData.homePin) {
                                errorInfo = `HomePin: ${matchData.homePin}`;
                            } else if (matchData.guestPin) {
                                errorInfo = `GuestPin: ${matchData.guestPin}`;
                            }
                            results.errors.push(`Teams nicht gefunden: "${matchData.homeTeamName}" oder "${matchData.guestTeamName}" (Datum: ${matchData.date.toISOString().split('T')[0]}, Zeit: ${matchData.time}, ${errorInfo})`);
                            continue;
                        }

                        // Erstelle neues Match (Fallback)
                        await Match.create({
                            date: matchData.date,
                            time: matchData.time,
                            homeTeamId: homeTeam.id,
                            guestTeamId: guestTeam.id,
                            leagueId: leagueId,
                            clubId: matchData.clubId,
                            code: matchData.code,
                            homePin: matchData.homePin,
                            guestPin: matchData.guestPin,
                            locationId: 1 // Default Location, kann später angepasst werden
                        });
                        results.created++;
                    }
                } catch (matchError) {
                    console.error('[PDFParserService.saveMatchesToDatabase] - Error:', matchError);
                    results.errors.push(`Fehler beim Speichern von Match: ${matchData.rawLine} - ${matchError.message}`);
                }
            }

            return results;
        } catch (error) {
            console.error('[PDFParserService.saveMatchesToDatabase] - Error:', error);
            throw error;
        }
    }

    static async extractPdfTextWithLayout(filePath) {
        const { default: pdfjsLib } = await import('pdfjs-dist/legacy/build/pdf.js');
        const pdfData = new Uint8Array(fs.readFileSync(filePath));
        const loadingTask = pdfjsLib.getDocument({ data: pdfData, disableWorker: true });
        const pdf = await loadingTask.promise;

        const lineEntries = [];
        const lineTolerance = 2; // Toleranz für Zeilenhöhe
        const spaceGapThreshold = 1.5; // Mindestabstand, um ein Leerzeichen einzufügen

        for (let pageNumber = 1; pageNumber <= pdf.numPages; pageNumber++) {
            const page = await pdf.getPage(pageNumber);
            const textContent = await page.getTextContent({ normalizeWhitespace: false });
            const pageLines = [];

            textContent.items.forEach((item) => {
                if (!item || typeof item.str !== 'string') {
                    return;
                }
                const text = item.str;
                if (!text || text.trim().length === 0) {
                    return;
                }

                const [scaleX, , , , x, y] = item.transform;
                const width = (item.width || 0) * (scaleX || 1);

                let targetLine = pageLines.find((line) => Math.abs(line.y - y) < lineTolerance);
                if (!targetLine) {
                    targetLine = { y, items: [] };
                    pageLines.push(targetLine);
                }

                targetLine.items.push({
                    text,
                    x,
                    y,
                    width
                });
            });

            // Sortiere Zeilen von oben nach unten
            pageLines.sort((a, b) => b.y - a.y);

            pageLines.forEach((line) => {
                // Sortiere Zeichen von links nach rechts
                line.items.sort((a, b) => a.x - b.x);

                let lineText = '';
                let previousItem = null;

                line.items.forEach((item) => {
                    if (previousItem) {
                        const previousEnd = previousItem.x + previousItem.width;
                        const gap = item.x - previousEnd;
                        if (gap > spaceGapThreshold) {
                            lineText += ' ';
                        }
                    }

                    lineText += item.text;
                    previousItem = item;
                });

                const normalized = lineText.trim();
                if (normalized.length > 0) {
                    lineEntries.push({
                        text: normalized,
                        items: line.items.map((item) => ({
                            text: item.text,
                            x: item.x,
                            y: item.y,
                            width: item.width
                        }))
                    });
                }
            });
        }

        await pdf.destroy();

        const lines = lineEntries.map((entry) => entry.text);
        const text = lines.join('\n');
        return { text, lines, entries: lineEntries };
    }

    static normalizeTeamName(name) {
        if (!name || typeof name !== 'string') return '';
        return name
            .toLowerCase()
            .replace(/\u2026/g, '...')
            .replace(/\s+/g, ' ')
            .trim();
    }

    static matchWithEllipsis(pattern, target) {
        const normalizedPattern = PDFParserService.normalizeTeamName(pattern);
        const normalizedTarget = PDFParserService.normalizeTeamName(target);

        if (!normalizedPattern.includes('...')) {
            return normalizedTarget.includes(normalizedPattern);
        }

        const segments = normalizedPattern.split('...').map(segment => segment.trim()).filter(Boolean);
        if (segments.length === 0) {
            return true;
        }

        let currentIndex = 0;
        for (const segment of segments) {
            const foundIndex = normalizedTarget.indexOf(segment, currentIndex);
            if (foundIndex === -1) {
                return false;
            }
            currentIndex = foundIndex + segment.length;
        }

        return true;
    }

    static namesRoughlyMatch(nameA, nameB) {
        const normalizedA = PDFParserService.normalizeTeamName(nameA);
        const normalizedB = PDFParserService.normalizeTeamName(nameB);

        if (!normalizedA || !normalizedB) {
            return false;
        }

        if (normalizedA === normalizedB) {
            return true;
        }

        if (normalizedA.includes('...') || normalizedB.includes('...')) {
            if (PDFParserService.matchWithEllipsis(normalizedA, normalizedB)) {
                return true;
            }
            if (PDFParserService.matchWithEllipsis(normalizedB, normalizedA)) {
                return true;
            }
        }

        return normalizedA.includes(normalizedB) || normalizedB.includes(normalizedA);
    }
}

export default PDFParserService;
