#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Utilitários de Paginação Inteligente para Relatórios PDF
Sistema para evitar espaços longos em branco nos relatórios
"""

from reportlab.platypus import PageBreak, Spacer, KeepTogether
from reportlab.lib.units import inch

class SmartPagination:
    """Classe para gerenciar paginação inteligente em relatórios PDF"""
    
    def __init__(self, page_height=11*inch, margin_top=1*inch, margin_bottom=1*inch):
        """
        Inicializa o gerenciador de paginação
        
        Args:
            page_height: Altura total da página em pontos
            margin_top: Margem superior em pontos
            margin_bottom: Margem inferior em pontos
        """
        self.page_height = page_height
        self.margin_top = margin_top
        self.margin_bottom = margin_bottom
        self.usable_height = page_height - margin_top - margin_bottom
        self.current_height = 0
        self.elements_buffer = []
        
    def add_element(self, element, estimated_height=None):
        """
        Adiciona um elemento ao buffer com estimativa de altura
        
        Args:
            element: Elemento ReportLab (Paragraph, Table, Image, etc.)
            estimated_height: Altura estimada em pontos (opcional)
        """
        if estimated_height is None:
            estimated_height = self._estimate_element_height(element)
        
        # Se o elemento não cabe na página atual, força quebra
        if self.current_height + estimated_height > self.usable_height:
            self._force_page_break()
        
        self.elements_buffer.append(element)
        self.current_height += estimated_height
    
    def add_with_break_if_needed(self, element, estimated_height=None, force_break=False):
        """
        Adiciona elemento com quebra de página inteligente se necessário
        
        Args:
            element: Elemento ReportLab
            estimated_height: Altura estimada em pontos
            force_break: Força quebra de página antes do elemento
        """
        if estimated_height is None:
            estimated_height = self._estimate_element_height(element)
        
        # Força quebra se solicitado ou se não cabe na página
        if force_break or (self.current_height + estimated_height > self.usable_height):
            if self.elements_buffer:  # Só adiciona quebra se há elementos no buffer
                self.elements_buffer.append(PageBreak())
            self.current_height = 0
        
        self.elements_buffer.append(element)
        self.current_height += estimated_height
    
    def add_group_with_break(self, elements, group_estimated_height=None):
        """
        Adiciona um grupo de elementos que devem ficar juntos
        
        Args:
            elements: Lista de elementos ReportLab
            group_estimated_height: Altura total estimada do grupo
        """
        if group_estimated_height is None:
            group_estimated_height = sum(self._estimate_element_height(elem) for elem in elements)
        
        # Se o grupo não cabe na página atual, força quebra
        if self.current_height + group_estimated_height > self.usable_height:
            if self.elements_buffer:  # Só adiciona quebra se há elementos no buffer
                self.elements_buffer.append(PageBreak())
            self.current_height = 0
        
        # Adiciona o grupo como KeepTogether se tiver múltiplos elementos
        if len(elements) > 1:
            self.elements_buffer.append(KeepTogether(elements))
        else:
            self.elements_buffer.extend(elements)
        
        self.current_height += group_estimated_height
    
    def add_spacer(self, height=0.2*inch):
        """
        Adiciona espaçamento inteligente
        
        Args:
            height: Altura do espaçamento
        """
        if self.current_height + height > self.usable_height:
            # Se não cabe, pula para próxima página
            self._force_page_break()
        else:
            self.elements_buffer.append(Spacer(1, height))
            self.current_height += height
    
    def _force_page_break(self):
        """Força quebra de página"""
        if self.elements_buffer:
            self.elements_buffer.append(PageBreak())
        self.current_height = 0
    
    def _estimate_element_height(self, element):
        """
        Estima a altura de um elemento ReportLab
        
        Args:
            element: Elemento ReportLab
            
        Returns:
            Altura estimada em pontos
        """
        # Estimativas baseadas no tipo de elemento
        if hasattr(element, '__class__'):
            class_name = element.__class__.__name__
            
            if class_name == 'Paragraph':
                # Estima baseado no texto e fonte
                text = str(element.text) if hasattr(element, 'text') else ''
                lines = max(1, len(text) // 80)  # Aproximadamente 80 chars por linha
                return lines * 14  # 14 pontos por linha
            
            elif class_name == 'Table':
                # Estima baseado no número de linhas
                rows = len(element._cellvalues) if hasattr(element, '_cellvalues') else 1
                return rows * 20 + 20  # 20 pontos por linha + cabeçalho
            
            elif class_name == 'Image':
                # Usa a altura real da imagem se disponível
                return getattr(element, 'drawHeight', 100)
            
            elif class_name == 'Spacer':
                # Usa a altura real do espaçador
                return getattr(element, 'height', 20)
            
            elif class_name == 'PageBreak':
                return 0  # Quebra de página não ocupa espaço
            
            elif class_name == 'KeepTogether':
                # Estima baseado nos elementos internos
                return sum(self._estimate_element_height(elem) for elem in element._content)
        
        # Fallback para elementos desconhecidos
        return 50
    
    def get_story(self):
        """
        Retorna a lista de elementos formatada para o PDF
        
        Returns:
            Lista de elementos ReportLab prontos para doc.build()
        """
        return self.elements_buffer.copy()
    
    def reset(self):
        """Reinicia o gerenciador de paginação"""
        self.current_height = 0
        self.elements_buffer = []

def create_smart_pagination(page_height=11*inch, margin_top=1*inch, margin_bottom=1*inch):
    """
    Função utilitária para criar um gerenciador de paginação inteligente
    
    Args:
        page_height: Altura total da página em pontos
        margin_top: Margem superior em pontos
        margin_bottom: Margem inferior em pontos
        
    Returns:
        Instância de SmartPagination
    """
    return SmartPagination(page_height, margin_top, margin_bottom)

# Constantes para estimativas de altura
HEIGHT_ESTIMATES = {
    'title': 50,           # Títulos grandes
    'heading': 30,         # Subtítulos
    'paragraph': 20,       # Parágrafos normais
    'table_header': 25,    # Cabeçalho de tabela
    'table_row': 18,       # Linha de tabela
    'spacer_small': 10,    # Espaçamento pequeno
    'spacer_medium': 20,   # Espaçamento médio
    'spacer_large': 40,    # Espaçamento grande
    'chart_small': 150,    # Gráfico pequeno
    'chart_medium': 250,   # Gráfico médio
    'chart_large': 350,    # Gráfico grande
    'logo': 100,           # Logo
}

def get_height_estimate(element_type, custom_height=None):
    """
    Obtém estimativa de altura para tipos de elementos
    
    Args:
        element_type: Tipo do elemento (chave em HEIGHT_ESTIMATES)
        custom_height: Altura personalizada (sobrescreve estimativa)
        
    Returns:
        Altura estimada em pontos
    """
    if custom_height is not None:
        return custom_height
    return HEIGHT_ESTIMATES.get(element_type, 30)

