
import { jsPDF } from 'jspdf';
import { replaceVariables } from '@/lib/appUtils';

const STANDARD_FONTS_MAP = {
    'helvetica': 'helvetica',
    'arial': 'helvetica',
    'sans-serif': 'helvetica',
    'times new roman': 'times',
    'times': 'times',
    'serif': 'times',
    'courier': 'courier',
    'courier new': 'courier',
    'monospace': 'courier',
    'georgia': 'times',
    'verdana': 'helvetica',
    'symbol': 'symbol',
    'zapfdingbats': 'zapfdingbats'
};

export const resolveFontName = (fontFamily) => {
    if (!fontFamily) return 'helvetica';
    const f = fontFamily.toLowerCase().replace(/['"]/g, '').trim().split(',')[0].trim();
    if (STANDARD_FONTS_MAP[f]) return STANDARD_FONTS_MAP[f];
    if (f.includes('courier') || f.includes('mono') || f.includes('code') || f.includes('consolas')) return 'courier';
    if (f.includes('times') || f.includes('serif') || f.includes('georgia') || f.includes('garamond')) return 'times';
    if (f.includes('symbol')) return 'symbol';
    if (f.includes('dingbats')) return 'zapfdingbats';
    return 'helvetica';
};

export const loadImage = (url, compression = { enabled: false }) => {
    return new Promise((resolve) => {
      if (!url) { resolve(null); return; }
      const img = new Image();
      img.crossOrigin = 'Anonymous';
      img.onload = async () => {
        let dataURL;
        let width = img.width;
        let height = img.height;
        try {
            const canvas = document.createElement('canvas');
            canvas.width = width;
            canvas.height = height;
            const ctx = canvas.getContext('2d');
            ctx.imageSmoothingEnabled = true;
            ctx.imageSmoothingQuality = 'high';
            ctx.drawImage(img, 0, 0, width, height);
            dataURL = canvas.toDataURL('image/png');
            resolve({ dataURL, width, height });
        } catch (err) { console.warn("Image processing failed", err); resolve(null); }
      };
      img.onerror = (e) => { console.warn(`Failed to load image at ${url}`, e); resolve(null); }
      img.src = url;
    });
};

export const parseColor = (colorStr) => {
    if (!colorStr) return { r: 0, g: 0, b: 0 };
    if (colorStr.startsWith('#')) {
        let hex = colorStr.slice(1);
        if (hex.length === 3) hex = hex.split('').map(c => c + c).join('');
        const r = parseInt(hex.slice(0, 2), 16);
        const g = parseInt(hex.slice(2, 4), 16);
        const b = parseInt(hex.slice(4, 6), 16);
        return { r: isNaN(r) ? 0 : r, g: isNaN(g) ? 0 : g, b: isNaN(b) ? 0 : b };
    }
    if (colorStr.startsWith('rgb')) {
        const matches = colorStr.match(/\d+/g);
        if (matches && matches.length >= 3) return { r: parseInt(matches[0]), g: parseInt(matches[1]), b: parseInt(matches[2]) };
    }
    return { r: 0, g: 0, b: 0 };
};

export const parseHtmlToSegments = (html, baseStyles = {}) => {
    if (typeof window === 'undefined') return [{ text: html, styles: baseStyles }];
    
    const div = document.createElement('div');
    div.innerHTML = html;
    
    const segments = [];
    
    const traverse = (node, currentStyles) => {
        if (node.nodeType === 3) { 
            if (node.textContent) {
                let text = node.textContent;
                text = text.replace(/\u00A0/g, ' '); 
                segments.push({ text, styles: { ...currentStyles } });
            }
        } else if (node.nodeType === 1) { 
            const newStyles = { ...currentStyles };
            const tagName = node.tagName.toLowerCase();
            
            if (tagName === 'b' || tagName === 'strong') newStyles.fontWeight = 'bold';
            if (tagName === 'i' || tagName === 'em') newStyles.fontStyle = 'italic';
            if (tagName === 'u') newStyles.textDecoration = 'underline'; 
            if (node.style.color) newStyles.color = node.style.color;
            if (node.style.fontSize) newStyles.fontSize = node.style.fontSize;
            if (node.style.textDecoration) newStyles.textDecoration = node.style.textDecoration;
            
            if (tagName === 'li') {
                 const parent = node.parentElement;
                 const isOrdered = parent && parent.tagName.toLowerCase() === 'ol';
                 let prefix = '• ';
                 if (isOrdered) {
                     const index = Array.from(parent.children).indexOf(node) + 1;
                     prefix = `${index}. `;
                 }
                 segments.push({ text: prefix, styles: { ...newStyles, fontWeight: 'bold' } });
            }

            if (tagName === 'hr') {
                segments.push({ isHr: true, styles: { ...newStyles } });
            }

            node.childNodes.forEach(child => traverse(child, newStyles));
            
            if (['p', 'div', 'li', 'br', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tagName)) {
                segments.push({ text: '\n', styles: { ...newStyles } });
            }
        }
    };
    
    traverse(div, baseStyles);
    return segments;
};

export const computeLines = (segments, doc, maxWidth, fontSize, fontFamily, alignment, fontAvailable = false) => {
    const lines = [];
    let currentLine = { words: [], width: 0, isHr: false, isLastInParagraph: false };
    
    segments.forEach(segment => {
        if (segment.isHr) {
             if (currentLine.words.length > 0) {
                 currentLine.isLastInParagraph = true;
                 lines.push(currentLine);
                 currentLine = { words: [], width: 0, isHr: false, isLastInParagraph: false };
             }
             lines.push({ isHr: true, width: maxWidth, words: [], isLastInParagraph: false });
             return;
        }

        const parts = segment.text.split('\n');
        
        parts.forEach((part, partIndex) => {
            if (partIndex > 0) {
                if (currentLine.words.length > 0) {
                    currentLine.isLastInParagraph = true;
                    lines.push(currentLine);
                }
                currentLine = { words: [], width: 0, isHr: false, isLastInParagraph: false };
            }

            const words = part.split(/(\s+)/); 
            
            words.forEach(word => {
                if (word.length === 0) return;
                
                const style = segment.styles.fontStyle || 'normal';
                const weight = segment.styles.fontWeight || 'normal';
                let pdfStyle = 'normal';
                if ((weight === 'bold' || parseInt(weight) >= 700) && style === 'italic') pdfStyle = 'bolditalic';
                else if (weight === 'bold' || parseInt(weight) >= 700) pdfStyle = 'bold';
                else if (style === 'italic') pdfStyle = 'italic';

                doc.setFont(fontFamily, pdfStyle);
                doc.setFontSize(fontSize);
                const segWidth = doc.getTextWidth(word);
                
                if (currentLine.width + segWidth > maxWidth && word.trim().length > 0 && currentLine.words.length > 0) {
                    lines.push(currentLine);
                    currentLine = { words: [], width: 0, isHr: false, isLastInParagraph: false };
                }
                
                currentLine.words.push({
                    text: word,
                    width: segWidth,
                    styles: segment.styles,
                    pdfStyle: pdfStyle,
                    isSymbol: false
                });
                currentLine.width += segWidth;
            });
        });
    });
    
    if (currentLine.words.length > 0) {
        currentLine.isLastInParagraph = true;
        lines.push(currentLine);
    }
    return lines;
};

export const renderLine = async (doc, line, x, y, maxWidth, alignment, fontSize, defaultColor, fontAvailable = false, fontFamily = 'helvetica') => {
    if (line.isHr) {
         doc.setDrawColor(200);
         doc.setLineWidth(1);
         doc.line(x, y + 5, x + maxWidth, y + 5);
         return 10;
    }

    let startX = x;
    let spacePerGap = 0;

    if (alignment === 'center') startX = x + (maxWidth - line.width) / 2;
    if (alignment === 'right') startX = x + (maxWidth - line.width);
    
    if (alignment === 'justify' && !line.isLastInParagraph) {
        const gaps = line.words.filter(w => w.text === ' ').length;
        if (gaps > 0 && line.width < maxWidth) {
             const extraSpace = maxWidth - line.width;
             spacePerGap = extraSpace / gaps;
        }
    }
    
    let currentX = startX;
    const maxHeight = fontSize; 
    
    for (const word of line.words) {
        let widthAdjustment = 0;
        if (alignment === 'justify' && word.text === ' ') {
            widthAdjustment = spacePerGap;
        }

        doc.setFontSize(fontSize); 
        doc.setFont(fontFamily, word.pdfStyle); 
        
        if (word.styles.color) {
            const c = parseColor(word.styles.color);
            doc.setTextColor(c.r, c.g, c.b);
        } else {
            doc.setTextColor(defaultColor.r, defaultColor.g, defaultColor.b);
        }
        
        doc.text(word.text, currentX, y);

        if (word.styles.underline || word.styles.textDecoration?.includes('underline')) {
            const underlineWidth = word.width + widthAdjustment;
            const underlineY = y + (fontSize * 0.1); 
            doc.setLineWidth(fontSize * 0.05);
            
            let lc = defaultColor;
            if (word.styles.color) lc = parseColor(word.styles.color);
            doc.setDrawColor(lc.r, lc.g, lc.b);

            doc.line(currentX, underlineY, currentX + underlineWidth, underlineY);
        }
        
        currentX += word.width + widthAdjustment;
    }
    
    return maxHeight;
};

export const drawBlock = async (doc, block, startY, pageWidth, margins, callbacks = {}, variables = {}, blocks = [], fontAvailable = false, globalSettings = {}) => {
    doc.setCharSpace(0);
    
    const lineWidthPercent = globalSettings.lineWidth || 100;
    const effectiveMaxWidth = (pageWidth - (margins.left || 54) - (margins.right || 54)) * (lineWidthPercent / 100);
    const margin = margins.left || 54;
    const pageHeight = doc.internal.pageSize.getHeight();
    const bottomMargin = margins.bottom || 72;
    let currentY = startY;

    if (!block) return currentY;
    
    if (block.type === 'page_break') { doc.addPage(); if (callbacks.onPageAdd) callbacks.onPageAdd(); return margins.top || 54; }
    if (block.type === 'spacer') return currentY + (block.styles?.height || block.styling?.height || 20);
    
    const combinedStyles = { ...(block.styles || {}), ...(block.styling || {}) };

    if (block.type === 'horizontal_line' || block.type === 'line') {
        doc.setDrawColor(200);
        doc.setLineWidth(1);
        if (combinedStyles.color) {
            const c = parseColor(combinedStyles.color);
            doc.setDrawColor(c.r, c.g, c.b);
        }
        const lineY = currentY + 10;
        doc.line(margin, lineY, margin + effectiveMaxWidth, lineY);
        return currentY + 20;
    }

    if (block.type === 'unified_text' || block.type === 'paragraph' || block.type === 'heading' || block.type === 'text' || block.type === 'text_section' || block.type === 'subtitle' || block.type === 'subsection') {
        let content = block.content || '';
        if (variables) content = replaceVariables(content, variables);
        
        const cssStyles = { ...combinedStyles };
        if (combinedStyles.underline) {
            cssStyles.textDecoration = 'underline';
        }
        
        const segments = parseHtmlToSegments(content, cssStyles);
        
        const fontFamily = resolveFontName(combinedStyles.fontFamily || 'Helvetica');
        const isTextType = block.type === 'text';
        const fontSize = parseInt(isTextType ? (combinedStyles.fontSize || 16) : (combinedStyles.fontSize || 9));
        const alignment = combinedStyles.textAlign || 'left';
        
        const lines = computeLines(segments, doc, effectiveMaxWidth, fontSize, fontFamily, alignment, fontAvailable);
        const lineHeightScale = combinedStyles.lineHeight || 1.5;

        for (const line of lines) {
             let maxLineFontSize = fontSize;
             if (line.words) line.words.forEach(w => { 
                 if (w.styles?.fontSize) {
                     const size = parseInt(w.styles.fontSize);
                     if (!isNaN(size) && size > maxLineFontSize) maxLineFontSize = size;
                 }
             });
             
             const estimatedHeight = line.isHr ? 10 : (maxLineFontSize * lineHeightScale);
             
             if (currentY + estimatedHeight > pageHeight - bottomMargin) {
                doc.addPage();
                if (callbacks.onPageAdd) callbacks.onPageAdd();
                currentY = margins.top || 54;
             }
             
             const renderY = currentY + (maxLineFontSize * 0.8); 
             const heightUsed = await renderLine(doc, line, margin, renderY, effectiveMaxWidth, alignment, fontSize, {r:0,g:0,b:0}, fontAvailable, fontFamily);
             
             currentY += line.isHr ? heightUsed : Math.max(heightUsed * lineHeightScale, fontSize * lineHeightScale);
        }

        if (combinedStyles.borderBottomStyle && combinedStyles.borderBottomStyle !== 'none') {
            const lineWidth = parseFloat(combinedStyles.borderBottomWidth) || 1;
            const lineColor = parseColor(combinedStyles.borderBottomColor || '#000000');
            const lineStyle = combinedStyles.borderBottomStyle;
            
            doc.setDrawColor(lineColor.r, lineColor.g, lineColor.b);
            doc.setLineWidth(lineWidth);
            
            if (lineStyle === 'dashed') {
                doc.setLineDash([lineWidth * 4, lineWidth * 2], 0);
            } else if (lineStyle === 'dotted') {
                doc.setLineDash([lineWidth, lineWidth], 0);
            } else {
                doc.setLineDash([], 0);
            }

            const dividerY = currentY + 2; 
            doc.line(margin, dividerY, margin + effectiveMaxWidth, dividerY);
            
            doc.setLineDash([], 0);
            currentY += lineWidth + 4;
        }

        currentY += (combinedStyles.marginBottom || 10);
    }
    
    return currentY;
};
