#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Gerador de PDF para o módulo Simulador
Baseado nas imagens fornecidas pelo usuário
"""

import os
import json
from datetime import datetime
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch, cm
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, Image, KeepTogether
from reportlab.lib import colors
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.graphics.shapes import Drawing, Rect, Line
from reportlab.graphics.charts.linecharts import HorizontalLineChart
from reportlab.graphics.charts.textlabels import Label
from reportlab.graphics import renderPDF
from .pdf_pagination_utils import (
    cond_page_break_before_large_figure,
    cond_page_break_before_footer_block,
    cond_page_break_before_subsection_with_figure,
)
from .i18n import get_translator as _get_translator, t
from .embedded_images import get_logo_image_bytes, get_risk_image_bytes
from .app_console import fc_log
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
import io

class SimuladorPDFGenerator:
    def __init__(self):
        self.styles = getSampleStyleSheet()
        self._setup_custom_styles()
    
    def _setup_custom_styles(self):
        """Configura estilos personalizados para o relatório"""
        # Título principal
        self.title_style = ParagraphStyle(
            'CustomTitle',
            parent=self.styles['Heading1'],
            fontSize=24,
            spaceAfter=30,
            alignment=TA_CENTER,
            textColor=colors.HexColor('#2c3e50'),
            fontName='Helvetica-Bold'
        )
        
        # Subtítulos
        self.heading_style = ParagraphStyle(
            'CustomHeading',
            parent=self.styles['Heading2'],
            fontSize=16,
            spaceAfter=12,
            textColor=colors.HexColor('#2c3e50'),
            fontName='Helvetica-Bold'
        )
        
        # Texto normal
        self.normal_style = ParagraphStyle(
            'CustomNormal',
            parent=self.styles['Normal'],
            fontSize=10,
            spaceAfter=6,
            fontName='Helvetica'
        )
        
        # Tabela de cabeçalho
        self.table_header_style = ParagraphStyle(
            'TableHeader',
            parent=self.styles['Normal'],
            fontSize=10,
            textColor=colors.white,
            fontName='Helvetica-Bold',
            alignment=TA_CENTER
        )

    def generate_pdf_report(self, simulador_data, output_path):
        """
        Gera o relatório PDF completo do simulador
        
        Args:
            simulador_data: Dados do simulador (slot_data, parâmetros globais, etc.)
            output_path: Caminho onde salvar o PDF
        """
        temp_files = []  # Lista para armazenar arquivos temporários
        try:
            # Cria o documento PDF
            doc = SimpleDocTemplate(
                output_path, 
                pagesize=A4,
                rightMargin=2*cm, 
                leftMargin=2*cm, 
                topMargin=2*cm, 
                bottomMargin=2*cm
            )
            
            # Lista única de flowables — sem SmartPagination (estimativas inflavam current_height e
            # geravam PageBreak extra + página em branco entre cabeçalho e matriz de risco).
            story = []
            story.extend(self._create_header_page(simulador_data))
            story.append(cond_page_break_before_subsection_with_figure(9.0 / 2.54))
            story.extend(self._create_risk_and_charts_page(simulador_data, temp_files))
            story.extend(self._create_individual_charts_pages(simulador_data, temp_files))
            story.extend(self._create_footer_page())
            
            # Gera o PDF
            doc.build(story)
            fc_log("simulador_pdf", f"✅ Relatório PDF do Simulator gerado: {output_path}")
            return True
            
        except Exception as e:
            fc_log("simulador_pdf", f"❌ Erro ao gerar PDF do Simulator: {e}")
            return False
        finally:
            # Remove arquivos temporários
            for temp_file in temp_files:
                try:
                    if os.path.exists(temp_file):
                        os.remove(temp_file)
                except:
                    pass

    def _create_header_page(self, simulador_data):
        """Cria a primeira página com cabeçalho de sistema e descrição do teste (no padrão Noise Check)."""
        story = []

        # Logo FastTag (embutido em memória)
        try:
            logo_bytes = get_logo_image_bytes()
            if logo_bytes:
                logo_buffer = io.BytesIO(logo_bytes)
                logo_size = 1.5 * inch
                logo_img = Image(logo_buffer, width=logo_size, height=logo_size)
                story.append(logo_img)
                story.append(Spacer(1, 10))
        except Exception as e:
            fc_log("simulador_pdf", f"⚠️ Erro ao adicionar logo no PDF do Simulator: {e}")

        # Título principal (módulo)
        story.append(Paragraph("Relatório de Testes - Simulator", self.title_style))
        story.append(Spacer(1, 20))

        # Bloco "Informações do Sistema"
        story.append(Paragraph(t('pdf.system_info'), self.heading_style))

        # Dados básicos de sistema (seguindo padrão geral)
        try:
            from .version_config import get_software_info
            software_info = get_software_info()
            software_label = software_info.get('software', 'FastChecker II')
        except Exception:
            software_label = "FastChecker II"

        translator = _get_translator()
        lang = translator.get_language() if translator else "pt"
        date_format = '%d/%m/%Y %H:%M:%S' if lang == 'pt' else '%m/%d/%y %I:%M:%S %p'
        generated_at = datetime.now().strftime(date_format)

        # Texto de licença vindo do módulo (já considera modo browser/licenciado)
        license_text = simulador_data.get('license') or t('simulator.pdf_license_fallback_browser')

        # Monta parágrafo rico como no Noise Check
        system_html = (
            f"<b>{t('pdf.software', 'Software')}</b> {software_label}<br/>"
            f"<b>{t('pdf.hardware', 'Hardware')}</b> v7.0<br/>"
            f"<b>{t('pdf.firmware', 'Firmware')}</b> v1.3.5<br/>"
            f"<b>{t('pdf.serial_number', 'Serial Number')}</b> FC01-EVT001<br/>"
            f"<b>{t('pdf.license', 'Licença')}</b> {license_text}<br/>"
            f"<b>{t('pdf.generated_at', 'Gerado em:')}</b> {generated_at}"
        )

        story.append(Paragraph(system_html, self.normal_style))
        story.append(Spacer(1, 20))

        # Bloco "Descrição do Teste" (padrão similar ao Noise Check)
        story.append(Paragraph(t('pdf.test_description_title_simulator', 'Descrição do Teste'), self.heading_style))
        story.append(Paragraph(
            t(
                'pdf.test_description_text_simulator',
                'Este relatório apresenta os resultados dos testes de desempenho de tags RFID realizados no módulo Simulator do FastChecker II. '
                'São destacados o comportamento do link forward, reverse e link final em função da frequência, considerando os limites de licença configurados.'
            ),
            self.normal_style
        ))
        story.append(Spacer(1, 20))

        # Configuração do teste
        story.append(Paragraph(t('pdf.test_config_title', 'Configuração do Teste'), self.heading_style))
        
        test_config = [
            [t('pdf.parameter'), t('pdf.value')],
            [t('simulator.pdf_config_irradiated_power'), str(simulador_data.get('reader_power', 36))],
            [t('simulator.pdf_config_sensitivity'), str(simulador_data.get('reader_sensitivity', -70))],
            [t('simulator.pdf_config_margin'), str(simulador_data.get('margin_db', 3.0))]
        ]
        
        config_table = Table(test_config, colWidths=[6*cm, 4*cm])
        config_table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#1f4e79')),
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
            ('FONTNAME', (0, 0), (-1, -1), 'Helvetica-Bold'),
            ('FONTSIZE', (0, 0), (-1, -1), 10),
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
            ('LEFTPADDING', (0, 0), (-1, -1), 6),
            ('RIGHTPADDING', (0, 0), (-1, -1), 6),
            ('TOPPADDING', (0, 0), (-1, -1), 6),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
            ('GRID', (0, 0), (-1, -1), 1, colors.black),
        ]))
        
        story.append(config_table)
        story.append(Spacer(1, 5))
        
        # Dados dos testes
        story.append(Paragraph(t('simulator.pdf_test_data_heading'), self.heading_style))
        
        test_data = self._prepare_test_data_table(simulador_data)
        test_table = Table(test_data, colWidths=[2*cm, 4*cm, 2.5*cm, 2.5*cm, 2.5*cm, 2.5*cm, 2.5*cm])
        test_table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#1f4e79')),
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
            ('FONTNAME', (0, 0), (-1, -1), 'Helvetica-Bold'),
            ('FONTSIZE', (0, 0), (-1, -1), 8),
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
            ('LEFTPADDING', (0, 0), (-1, -1), 3),
            ('RIGHTPADDING', (0, 0), (-1, -1), 3),
            ('TOPPADDING', (0, 0), (-1, -1), 3),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 3),
            ('GRID', (0, 0), (-1, -1), 1, colors.black),
        ]))
        
        story.append(test_table)
        story.append(Spacer(1, 5))
        
        return story

    def _create_risk_and_charts_page(self, simulador_data, temp_files):
        """Cria a segunda página com tabelas de risco e gráficos"""
        story = []

        # Seção de risco com a mesma imagem utilizada na tela (embutida em memória)
        try:
            translator = _get_translator()
            lang = translator.get_language() if translator else "pt"
            risk_bytes = get_risk_image_bytes("en" if lang == "en" else "pt")

            if risk_bytes:
                risk_buffer = io.BytesIO(risk_bytes)
                # Ajuste de tamanho para ficar próximo ao exibido na tela
                risk_img = Image(risk_buffer, width=7*cm, height=9*cm)
                # Título + imagem sempre juntos (evita título órfão no fim de página)
                story.append(
                    KeepTogether(
                        [
                            Paragraph(t('simulator.pdf_risk_table_heading'), self.heading_style),
                            Spacer(1, 5),
                            risk_img,
                        ]
                    )
                )
                story.append(Spacer(1, 10))
                fc_log("simulador_pdf", "✅ Tabela de risco (imagem) adicionada ao PDF do Simulator")
            else:
                fc_log("simulador_pdf", "⚠️ Não foi possível carregar a imagem da tabela de risco")
        except Exception as e:
            fc_log("simulador_pdf", f"⚠️ Erro ao adicionar imagem de risco no PDF: {e}")
        
        # Gráfico do Slot 1
        if simulador_data.get('slot_data') and simulador_data['slot_data'][0]:
            # Título do gráfico
            story.append(Paragraph(t('pdf.test_charts'), self.heading_style))
            story.append(Spacer(1, 1))
            story.append(Paragraph(t('simulator.pdf_slot1_chart'), self.heading_style))
            story.append(Spacer(1, 1))
            
            chart_bytes = self._create_frequency_chart(simulador_data['slot_data'][0], t('simulator.pdf_slot1_chart'))
            if chart_bytes:
                story.append(Image(io.BytesIO(chart_bytes), width=15*cm, height=8*cm))
        
        return story

    def _create_individual_charts_pages(self, simulador_data, temp_files):
        """Cria as páginas com gráficos individuais dos slots com paginação inteligente"""
        story = []
        
        slot_data = simulador_data.get('slot_data', [])
        
        # Página 1: Slots 2 e 3 (se existirem)
        if len(slot_data) > 1 and slot_data[1]:
            # Título do gráfico
            story.append(Paragraph(t('simulator.pdf_slot2_chart'), self.heading_style))
            story.append(Spacer(1, 1))
            
            chart_bytes = self._create_frequency_chart(slot_data[1], t('simulator.pdf_slot2_chart'))
            if chart_bytes:
                story.append(Image(io.BytesIO(chart_bytes), width=15*cm, height=8*cm))
        
        # Slot 3 na mesma página (se existir)
        if len(slot_data) > 2 and slot_data[2]:
            # Título do gráfico
            story.append(Spacer(1, 1))
            story.append(Paragraph(t('simulator.pdf_slot3_chart'), self.heading_style))
            story.append(Spacer(1, 1))
            
            chart_bytes = self._create_frequency_chart(slot_data[2], t('simulator.pdf_slot3_chart'))
            if chart_bytes:
                story.append(Image(io.BytesIO(chart_bytes), width=15*cm, height=8*cm))
        
        # Slot 4: nova página só se não couber o gráfico no espaço restante
        if len(slot_data) > 3 and slot_data[3]:
            story.append(cond_page_break_before_large_figure(8 / 2.54))
            # Título do gráfico
            story.append(Paragraph(t('simulator.pdf_slot4_chart'), self.heading_style))
            story.append(Spacer(1, 1))
            
            chart_bytes = self._create_frequency_chart(slot_data[3], t('simulator.pdf_slot4_chart'))
            if chart_bytes:
                story.append(Image(io.BytesIO(chart_bytes), width=15*cm, height=8*cm))
        
        return story

    def _create_frequency_chart(self, slot_data, title):
        """Cria gráfico de distância vs frequência para um slot"""
        try:
            if not slot_data or 'data' not in slot_data or slot_data['data'].empty:
                return None
            
            df = slot_data['data']
            
            # Cria figura com proporção adequada
            fig, ax = plt.subplots(figsize=(14, 8))
            
            # Dados para o gráfico
            frequency = df['Frequência'].values if hasattr(df['Frequência'], 'values') else df['Frequência']
            forward_link = df['Forward Link'].values if hasattr(df['Forward Link'], 'values') else df['Forward Link']
            reverse_link = df['Reverse Link'].values if hasattr(df['Reverse Link'], 'values') else df['Reverse Link']
            link_final = df['Link Final'].values if hasattr(df['Link Final'], 'values') else df['Link Final']
            link_final_margin_data = df.get('Link Final (Margem 3.0 dB)', link_final * 0.7)
            link_final_margin = link_final_margin_data.values if hasattr(link_final_margin_data, 'values') else link_final_margin_data
            
            # Plota as linhas – mesma lógica visual da tela
            ax.plot(df['Frequência'], df['Forward Link'], marker='.', linestyle='-', label=t('simulator.graph_forward_link'), linewidth=1.0, markersize=4)
            ax.plot(df['Frequência'], df['Reverse Link'], marker='.', linestyle='-', label=t('simulator.graph_reverse_link'), linewidth=1.0, markersize=4)
            ax.plot(df['Frequência'], df['Link Final'], marker='.', linestyle='-', label=t('simulator.graph_link_final'), linewidth=1.8, color='black', markersize=4)
            # Curva de margem opcional (se existir, imita tela)
            if 'Link Final Margin' in df.columns:
                ax.plot(df['Frequência'], df['Link Final Margin'], marker='.', linestyle='--', color='red',
                        label=t('simulator.graph_link_final_margin').format(margin='3.0'), linewidth=1.5, markersize=4)
            
            # Títulos, eixos, legenda e grade iguais aos gráficos da UI
            ax.set_title(title, fontsize=10)
            ax.set_xlabel(t('simulator.graph_frequency'))
            ax.set_ylabel(t('simulator.graph_distance'))
            ax.legend(fontsize=7, loc='best', framealpha=0.6)
            ax.grid(True, which='both', linestyle='--', linewidth=0.5)
            
            # Ajuste de escala idêntico ao usado na tela
            x_min = df['Frequência'].min()
            x_max = df['Frequência'].max()
            y_max = max(df['Forward Link'].max(), df['Reverse Link'].max(), df['Link Final'].max())
            if 'Link Final Margin' in df.columns:
                y_max = max(y_max, df['Link Final Margin'].max())
            
            x_span = x_max - x_min
            x_margin = max(0.5, x_span * 0.05)
            y_margin = y_max * 0.05
            
            x_plot_min = x_min - x_margin
            x_plot_max = x_max + x_margin
            ax.set_xlim(x_plot_min, x_plot_max)
            ax.set_ylim(0, y_max + y_margin)

            # Faixas regulatórias apenas quando sobrepõem a faixa exibida no gráfico.
            regulatory_bands = [
                (865.0, 868.0),
                (902.0, 907.0),
                (915.5, 928.0),
            ]
            for band_min, band_max in regulatory_bands:
                if not (band_max < x_plot_min or band_min > x_plot_max):
                    ax.axvspan(band_min, band_max, color='lightblue', alpha=0.3)
            
            # Salva em buffer em memória
            import io
            buffer = io.BytesIO()
            plt.tight_layout()
            plt.savefig(buffer, format='png', dpi=300, bbox_inches='tight')
            plt.close()
            buffer.seek(0)
            return buffer.getvalue()
            
        except Exception as e:
            fc_log("simulador_pdf", f"❌ Erro ao criar gráfico: {e}")
            return None

    def _prepare_test_data_table(self, simulador_data):
        """Prepara dados para a tabela de testes"""
        headers = [
            t('simulator.pdf_tests_header_slot'),
            t('simulator.pdf_tests_header_test_name'),
            t('simulator.pdf_tests_header_distance'),
            t('simulator.pdf_tests_header_attenuator'),
            t('simulator.pdf_tests_header_forward'),
            t('simulator.pdf_tests_header_reverse'),
            t('simulator.pdf_tests_header_final'),
        ]
        data = [headers]
        
        slot_data = simulador_data.get('slot_data', [])
        
        for i, slot in enumerate(slot_data):
            if slot and 'data' in slot and not slot['data'].empty:
                df = slot['data']
                test_name = slot.get('test_description', f'T{i+1}')
                distance = slot.get('params', {}).get('d_med', 'N/A')
                attenuator = slot.get('params', {}).get('atenuador', 'N/A')
                
                forward_max = f"{df['Forward Link'].max():.1f}" if 'Forward Link' in df.columns else "N/A"
                reverse_max = f"{df['Reverse Link'].max():.1f}" if 'Reverse Link' in df.columns else "N/A"
                link_final_max = f"{df['Link Final'].max():.1f}" if 'Link Final' in df.columns else "N/A"
                
                data.append([
                    t('simulator.pdf_tests_slot_row').format(n=i + 1),
                    test_name,
                    str(distance) if distance != 'N/A' else 'N/A',
                    str(attenuator) if attenuator != 'N/A' else 'N/A',
                    forward_max,
                    reverse_max,
                    link_final_max
                ])
            else:
                data.append([
                    t('simulator.pdf_tests_slot_row').format(n=i + 1),
                    "N/A",
                    "N/A",
                    "N/A",
                    "N/A",
                    "N/A",
                    "N/A"
                ])
        
        return data

    def _create_footer_page(self):
        """Cria página final com rodapé e informações adicionais"""
        story = []
        
        story.append(cond_page_break_before_footer_block())
        story.append(Spacer(1, 12))
        
        # Título da seção
        story.append(Paragraph(t('pdf.additional_info'), self.heading_style))
        story.append(Spacer(1, 20))
        
        story.append(Paragraph(t('pdf.footer_text'), self.normal_style))
        story.append(Spacer(1, 20))
        
        # Timestamp de geração - formata conforme idioma
        translator = _get_translator()
        current_lang = translator.get_language()
        if current_lang == 'en':
            timestamp = datetime.now().strftime("%m/%d/%y at %I:%M:%S %p")
        else:
            timestamp = datetime.now().strftime("%d/%m/%Y às %H:%M:%S")
        story.append(Paragraph(f"<b>{t('pdf.document_generated_at')}</b> {timestamp}", self.normal_style))
        
        return story
