"""
Audit Session PDF Report Generator.

Sprint 3 Phase 4: Generates PDF reports for completed audit sessions.

Features:
- Cover page with audit session metadata
- Executive summary with traffic light status
- Statistics pie chart (compliant/non-compliant/pending)
- Detailed checklist with sign-off status
- Digital signature verification
- Appendix with non-compliant items

Uses reportlab for PDF generation (lightweight, no external dependencies).
"""

import io
import logging
from datetime import datetime
from typing import Dict, List, Any, Optional, Tuple
from uuid import uuid4
import hashlib

from sqlalchemy.orm import Session, selectinload

from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm, cm
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT, TA_JUSTIFY
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    PageBreak, Image, ListFlowable, ListItem, KeepTogether,
    HRFlowable
)
from reportlab.graphics.shapes import Drawing, Rect, String
from reportlab.graphics.charts.piecharts import Pie

from ..db.models import (
    AuditSessionDB, AuditSignOffDB, AuditResultEnum, AuditSessionStatusEnum,
    RequirementDB, RegulationDB
)

logger = logging.getLogger(__name__)


# =============================================================================
# Color Definitions
# =============================================================================

COLORS = {
    'primary': colors.HexColor('#1a365d'),      # Dark blue
    'secondary': colors.HexColor('#2c5282'),    # Medium blue
    'accent': colors.HexColor('#3182ce'),       # Light blue
    'success': colors.HexColor('#38a169'),      # Green
    'warning': colors.HexColor('#d69e2e'),      # Yellow/Orange
    'danger': colors.HexColor('#e53e3e'),       # Red
    'muted': colors.HexColor('#718096'),        # Gray
    'light': colors.HexColor('#f7fafc'),        # Light gray
    'white': colors.white,
    'black': colors.black,
}

RESULT_COLORS = {
    'compliant': COLORS['success'],
    'compliant_notes': colors.HexColor('#68d391'),  # Light green
    'non_compliant': COLORS['danger'],
    'not_applicable': COLORS['muted'],
    'pending': COLORS['warning'],
}


# =============================================================================
# Custom Styles
# =============================================================================

def get_custom_styles() -> Dict[str, ParagraphStyle]:
    """Create custom paragraph styles for the audit report."""
    styles = getSampleStyleSheet()

    custom = {
        'Title': ParagraphStyle(
            'AuditTitle',
            parent=styles['Title'],
            fontSize=24,
            textColor=COLORS['primary'],
            spaceAfter=12*mm,
            alignment=TA_CENTER,
        ),
        'Subtitle': ParagraphStyle(
            'AuditSubtitle',
            parent=styles['Normal'],
            fontSize=14,
            textColor=COLORS['secondary'],
            spaceAfter=6*mm,
            alignment=TA_CENTER,
        ),
        'Heading1': ParagraphStyle(
            'AuditH1',
            parent=styles['Heading1'],
            fontSize=18,
            textColor=COLORS['primary'],
            spaceBefore=12*mm,
            spaceAfter=6*mm,
            borderPadding=3*mm,
        ),
        'Heading2': ParagraphStyle(
            'AuditH2',
            parent=styles['Heading2'],
            fontSize=14,
            textColor=COLORS['secondary'],
            spaceBefore=8*mm,
            spaceAfter=4*mm,
        ),
        'Heading3': ParagraphStyle(
            'AuditH3',
            parent=styles['Heading3'],
            fontSize=12,
            textColor=COLORS['accent'],
            spaceBefore=6*mm,
            spaceAfter=3*mm,
        ),
        'Normal': ParagraphStyle(
            'AuditNormal',
            parent=styles['Normal'],
            fontSize=10,
            textColor=COLORS['black'],
            spaceAfter=3*mm,
            alignment=TA_JUSTIFY,
        ),
        'Small': ParagraphStyle(
            'AuditSmall',
            parent=styles['Normal'],
            fontSize=8,
            textColor=COLORS['muted'],
            spaceAfter=2*mm,
        ),
        'Footer': ParagraphStyle(
            'AuditFooter',
            parent=styles['Normal'],
            fontSize=8,
            textColor=COLORS['muted'],
            alignment=TA_CENTER,
        ),
        'Success': ParagraphStyle(
            'AuditSuccess',
            parent=styles['Normal'],
            fontSize=10,
            textColor=COLORS['success'],
        ),
        'Warning': ParagraphStyle(
            'AuditWarning',
            parent=styles['Normal'],
            fontSize=10,
            textColor=COLORS['warning'],
        ),
        'Danger': ParagraphStyle(
            'AuditDanger',
            parent=styles['Normal'],
            fontSize=10,
            textColor=COLORS['danger'],
        ),
    }

    return custom


# =============================================================================
# PDF Generator Class
# =============================================================================

class AuditPDFGenerator:
    """Generates PDF reports for audit sessions."""

    def __init__(self, db: Session):
        self.db = db
        self.styles = get_custom_styles()
        self.page_width, self.page_height = A4
        self.margin = 20 * mm

    def generate(
        self,
        session_id: str,
        language: str = 'de',
        include_signatures: bool = True,
    ) -> Tuple[bytes, str]:
        """
        Generate a PDF report for an audit session.

        Args:
            session_id: The audit session ID
            language: Report language ('de' or 'en')
            include_signatures: Whether to include digital signature info

        Returns:
            Tuple of (PDF bytes, filename)
        """
        # Load session with all related data
        session = self._load_session(session_id)
        if not session:
            raise ValueError(f"Audit session {session_id} not found")

        # Load all sign-offs
        signoffs = self._load_signoffs(session_id)
        signoff_map = {s.requirement_id: s for s in signoffs}

        # Load requirements for this session
        requirements = self._load_requirements(session)

        # Calculate statistics
        stats = self._calculate_statistics(session, signoffs)

        # Generate PDF
        buffer = io.BytesIO()
        doc = SimpleDocTemplate(
            buffer,
            pagesize=A4,
            leftMargin=self.margin,
            rightMargin=self.margin,
            topMargin=self.margin,
            bottomMargin=self.margin,
        )

        # Build story (content)
        story = []

        # 1. Cover page
        story.extend(self._build_cover_page(session, language))
        story.append(PageBreak())

        # 2. Executive summary
        story.extend(self._build_executive_summary(session, stats, language))
        story.append(PageBreak())

        # 3. Statistics overview
        story.extend(self._build_statistics_section(stats, language))

        # 4. Detailed checklist
        story.extend(self._build_checklist_section(
            session, requirements, signoff_map, language
        ))

        # 5. Non-compliant items appendix (if any)
        non_compliant = [s for s in signoffs if s.result == AuditResultEnum.NON_COMPLIANT]
        if non_compliant:
            story.append(PageBreak())
            story.extend(self._build_non_compliant_appendix(
                non_compliant, requirements, language
            ))

        # 6. Signature verification (if requested)
        if include_signatures:
            signed_items = [s for s in signoffs if s.signature_hash]
            if signed_items:
                story.append(PageBreak())
                story.extend(self._build_signature_section(signed_items, language))

        # Build the PDF
        doc.build(story)

        # Generate filename
        date_str = datetime.utcnow().strftime('%Y%m%d')
        filename = f"audit_report_{session.name.replace(' ', '_')}_{date_str}.pdf"

        return buffer.getvalue(), filename

    def _load_session(self, session_id: str) -> Optional[AuditSessionDB]:
        """Load an audit session by ID."""
        return self.db.query(AuditSessionDB).filter(
            AuditSessionDB.id == session_id
        ).first()

    def _load_signoffs(self, session_id: str) -> List[AuditSignOffDB]:
        """Load all sign-offs for a session."""
        return (
            self.db.query(AuditSignOffDB)
            .filter(AuditSignOffDB.session_id == session_id)
            .all()
        )

    def _load_requirements(self, session: AuditSessionDB) -> List[RequirementDB]:
        """Load requirements for a session based on filters."""
        query = self.db.query(RequirementDB).join(RegulationDB)

        if session.regulation_ids:
            query = query.filter(RegulationDB.code.in_(session.regulation_ids))

        return query.order_by(RegulationDB.code, RequirementDB.article).all()

    def _calculate_statistics(
        self,
        session: AuditSessionDB,
        signoffs: List[AuditSignOffDB],
    ) -> Dict[str, Any]:
        """Calculate audit statistics."""
        total = session.total_items
        completed = len(signoffs)

        compliant = sum(1 for s in signoffs if s.result == AuditResultEnum.COMPLIANT)
        compliant_notes = sum(1 for s in signoffs if s.result == AuditResultEnum.COMPLIANT_WITH_NOTES)
        non_compliant = sum(1 for s in signoffs if s.result == AuditResultEnum.NON_COMPLIANT)
        not_applicable = sum(1 for s in signoffs if s.result == AuditResultEnum.NOT_APPLICABLE)
        pending = total - completed

        # Calculate compliance rate (excluding N/A and pending)
        applicable = compliant + compliant_notes + non_compliant
        compliance_rate = ((compliant + compliant_notes) / applicable * 100) if applicable > 0 else 0

        return {
            'total': total,
            'completed': completed,
            'pending': pending,
            'compliant': compliant,
            'compliant_notes': compliant_notes,
            'non_compliant': non_compliant,
            'not_applicable': not_applicable,
            'completion_percentage': round((completed / total * 100) if total > 0 else 0, 1),
            'compliance_rate': round(compliance_rate, 1),
            'traffic_light': self._determine_traffic_light(compliance_rate, pending, total),
        }

    def _determine_traffic_light(
        self,
        compliance_rate: float,
        pending: int,
        total: int,
    ) -> str:
        """Determine traffic light status."""
        pending_ratio = pending / total if total > 0 else 0

        if pending_ratio > 0.3:
            return 'yellow'  # Too many pending items
        elif compliance_rate >= 90:
            return 'green'
        elif compliance_rate >= 70:
            return 'yellow'
        else:
            return 'red'

    # =========================================================================
    # Build Page Sections
    # =========================================================================

    def _build_cover_page(
        self,
        session: AuditSessionDB,
        language: str,
    ) -> List:
        """Build the cover page."""
        story = []

        # Title
        title = 'AUDIT-BERICHT' if language == 'de' else 'AUDIT REPORT'
        story.append(Spacer(1, 30*mm))
        story.append(Paragraph(title, self.styles['Title']))

        # Session name
        story.append(Paragraph(session.name, self.styles['Subtitle']))
        story.append(Spacer(1, 15*mm))

        # Horizontal rule
        story.append(HRFlowable(
            width="80%",
            thickness=1,
            color=COLORS['accent'],
            spaceAfter=15*mm,
        ))

        # Metadata table
        labels = {
            'de': {
                'auditor': 'Auditor',
                'organization': 'Organisation',
                'status': 'Status',
                'created': 'Erstellt am',
                'started': 'Gestartet am',
                'completed': 'Abgeschlossen am',
                'regulations': 'Verordnungen',
            },
            'en': {
                'auditor': 'Auditor',
                'organization': 'Organization',
                'status': 'Status',
                'created': 'Created',
                'started': 'Started',
                'completed': 'Completed',
                'regulations': 'Regulations',
            },
        }
        l = labels.get(language, labels['de'])

        status_map = {
            'draft': 'Entwurf' if language == 'de' else 'Draft',
            'in_progress': 'In Bearbeitung' if language == 'de' else 'In Progress',
            'completed': 'Abgeschlossen' if language == 'de' else 'Completed',
            'archived': 'Archiviert' if language == 'de' else 'Archived',
        }

        data = [
            [l['auditor'], session.auditor_name],
            [l['organization'], session.auditor_organization or '-'],
            [l['status'], status_map.get(session.status.value, session.status.value)],
            [l['created'], session.created_at.strftime('%d.%m.%Y %H:%M') if session.created_at else '-'],
            [l['started'], session.started_at.strftime('%d.%m.%Y %H:%M') if session.started_at else '-'],
            [l['completed'], session.completed_at.strftime('%d.%m.%Y %H:%M') if session.completed_at else '-'],
            [l['regulations'], ', '.join(session.regulation_ids) if session.regulation_ids else 'Alle'],
        ]

        table = Table(data, colWidths=[50*mm, 100*mm])
        table.setStyle(TableStyle([
            ('FONTNAME', (0, 0), (0, -1), 'Helvetica-Bold'),
            ('FONTNAME', (1, 0), (1, -1), 'Helvetica'),
            ('FONTSIZE', (0, 0), (-1, -1), 11),
            ('TEXTCOLOR', (0, 0), (0, -1), COLORS['secondary']),
            ('TEXTCOLOR', (1, 0), (1, -1), COLORS['black']),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 8),
            ('TOPPADDING', (0, 0), (-1, -1), 8),
            ('ALIGN', (0, 0), (0, -1), 'RIGHT'),
            ('ALIGN', (1, 0), (1, -1), 'LEFT'),
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ]))

        story.append(table)
        story.append(Spacer(1, 20*mm))

        # Description if available
        if session.description:
            desc_label = 'Beschreibung' if language == 'de' else 'Description'
            story.append(Paragraph(f"<b>{desc_label}:</b>", self.styles['Normal']))
            story.append(Paragraph(session.description, self.styles['Normal']))

        # Generation timestamp
        story.append(Spacer(1, 30*mm))
        gen_label = 'Generiert am' if language == 'de' else 'Generated on'
        story.append(Paragraph(
            f"{gen_label}: {datetime.utcnow().strftime('%d.%m.%Y %H:%M')} UTC",
            self.styles['Footer']
        ))

        return story

    def _build_executive_summary(
        self,
        session: AuditSessionDB,
        stats: Dict[str, Any],
        language: str,
    ) -> List:
        """Build the executive summary section."""
        story = []

        title = 'ZUSAMMENFASSUNG' if language == 'de' else 'EXECUTIVE SUMMARY'
        story.append(Paragraph(title, self.styles['Heading1']))

        # Traffic light status
        traffic_light = stats['traffic_light']
        tl_colors = {
            'green': COLORS['success'],
            'yellow': COLORS['warning'],
            'red': COLORS['danger'],
        }
        tl_labels = {
            'de': {'green': 'GUT', 'yellow': 'AUFMERKSAMKEIT', 'red': 'KRITISCH'},
            'en': {'green': 'GOOD', 'yellow': 'ATTENTION', 'red': 'CRITICAL'},
        }

        # Create traffic light indicator
        tl_table = Table(
            [[tl_labels[language][traffic_light]]],
            colWidths=[60*mm],
            rowHeights=[15*mm],
        )
        tl_table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (0, 0), tl_colors[traffic_light]),
            ('TEXTCOLOR', (0, 0), (0, 0), COLORS['white']),
            ('FONTNAME', (0, 0), (0, 0), 'Helvetica-Bold'),
            ('FONTSIZE', (0, 0), (0, 0), 16),
            ('ALIGN', (0, 0), (0, 0), 'CENTER'),
            ('VALIGN', (0, 0), (0, 0), 'MIDDLE'),
            ('ROUNDEDCORNERS', [3, 3, 3, 3]),
        ]))

        story.append(tl_table)
        story.append(Spacer(1, 10*mm))

        # Key metrics
        labels = {
            'de': {
                'completion': 'Abschlussrate',
                'compliance': 'Konformitaetsrate',
                'total': 'Gesamtanforderungen',
                'non_compliant': 'Nicht konform',
                'pending': 'Ausstehend',
            },
            'en': {
                'completion': 'Completion Rate',
                'compliance': 'Compliance Rate',
                'total': 'Total Requirements',
                'non_compliant': 'Non-Compliant',
                'pending': 'Pending',
            },
        }
        l = labels.get(language, labels['de'])

        metrics_data = [
            [l['completion'], f"{stats['completion_percentage']}%"],
            [l['compliance'], f"{stats['compliance_rate']}%"],
            [l['total'], str(stats['total'])],
            [l['non_compliant'], str(stats['non_compliant'])],
            [l['pending'], str(stats['pending'])],
        ]

        metrics_table = Table(metrics_data, colWidths=[60*mm, 40*mm])
        metrics_table.setStyle(TableStyle([
            ('FONTNAME', (0, 0), (0, -1), 'Helvetica-Bold'),
            ('FONTNAME', (1, 0), (1, -1), 'Helvetica'),
            ('FONTSIZE', (0, 0), (-1, -1), 12),
            ('TEXTCOLOR', (0, 0), (0, -1), COLORS['secondary']),
            ('TEXTCOLOR', (1, 0), (1, -1), COLORS['black']),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
            ('TOPPADDING', (0, 0), (-1, -1), 6),
            ('ALIGN', (0, 0), (0, -1), 'LEFT'),
            ('ALIGN', (1, 0), (1, -1), 'RIGHT'),
            ('LINEABOVE', (0, 0), (-1, 0), 1, COLORS['light']),
            ('LINEBELOW', (0, -1), (-1, -1), 1, COLORS['light']),
        ]))

        story.append(metrics_table)
        story.append(Spacer(1, 10*mm))

        # Key findings
        findings_title = 'Wichtige Erkenntnisse' if language == 'de' else 'Key Findings'
        story.append(Paragraph(f"<b>{findings_title}:</b>", self.styles['Heading3']))

        findings = self._generate_findings(stats, language)
        for finding in findings:
            story.append(Paragraph(f"• {finding}", self.styles['Normal']))

        return story

    def _generate_findings(self, stats: Dict[str, Any], language: str) -> List[str]:
        """Generate key findings based on statistics."""
        findings = []

        if language == 'de':
            if stats['non_compliant'] > 0:
                findings.append(
                    f"{stats['non_compliant']} Anforderungen sind nicht konform und "
                    f"erfordern Massnahmen."
                )
            if stats['pending'] > 0:
                findings.append(
                    f"{stats['pending']} Anforderungen wurden noch nicht geprueft."
                )
            if stats['compliance_rate'] >= 90:
                findings.append(
                    "Hohe Konformitaetsrate erreicht. Weiter so!"
                )
            elif stats['compliance_rate'] < 70:
                findings.append(
                    "Konformitaetsrate unter 70%. Priorisierte Massnahmen erforderlich."
                )
            if stats['compliant_notes'] > 0:
                findings.append(
                    f"{stats['compliant_notes']} Anforderungen sind konform mit Anmerkungen. "
                    f"Verbesserungspotenzial identifiziert."
                )
            if not findings:
                findings.append("Audit vollstaendig abgeschlossen ohne kritische Befunde.")
        else:
            if stats['non_compliant'] > 0:
                findings.append(
                    f"{stats['non_compliant']} requirements are non-compliant and "
                    f"require action."
                )
            if stats['pending'] > 0:
                findings.append(
                    f"{stats['pending']} requirements have not been reviewed yet."
                )
            if stats['compliance_rate'] >= 90:
                findings.append(
                    "High compliance rate achieved. Keep up the good work!"
                )
            elif stats['compliance_rate'] < 70:
                findings.append(
                    "Compliance rate below 70%. Prioritized actions required."
                )
            if stats['compliant_notes'] > 0:
                findings.append(
                    f"{stats['compliant_notes']} requirements are compliant with notes. "
                    f"Improvement potential identified."
                )
            if not findings:
                findings.append("Audit completed without critical findings.")

        return findings

    def _build_statistics_section(
        self,
        stats: Dict[str, Any],
        language: str,
    ) -> List:
        """Build the statistics overview section with pie chart."""
        story = []

        title = 'STATISTIK-UEBERSICHT' if language == 'de' else 'STATISTICS OVERVIEW'
        story.append(Paragraph(title, self.styles['Heading1']))

        # Create pie chart
        drawing = Drawing(200, 200)
        pie = Pie()
        pie.x = 50
        pie.y = 25
        pie.width = 100
        pie.height = 100

        # Data for pie chart
        data = [
            stats['compliant'],
            stats['compliant_notes'],
            stats['non_compliant'],
            stats['not_applicable'],
            stats['pending'],
        ]

        # Only include non-zero values
        labels_de = ['Konform', 'Konform (Anm.)', 'Nicht konform', 'N/A', 'Ausstehend']
        labels_en = ['Compliant', 'Compliant (Notes)', 'Non-Compliant', 'N/A', 'Pending']
        labels = labels_de if language == 'de' else labels_en

        pie_colors = [
            COLORS['success'],
            colors.HexColor('#68d391'),
            COLORS['danger'],
            COLORS['muted'],
            COLORS['warning'],
        ]

        # Filter out zero values
        filtered_data = []
        filtered_labels = []
        filtered_colors = []
        for i, val in enumerate(data):
            if val > 0:
                filtered_data.append(val)
                filtered_labels.append(labels[i])
                filtered_colors.append(pie_colors[i])

        if filtered_data:
            pie.data = filtered_data
            pie.labels = filtered_labels
            pie.slices.strokeWidth = 0.5

            for i, col in enumerate(filtered_colors):
                pie.slices[i].fillColor = col

            drawing.add(pie)
            story.append(drawing)
        else:
            no_data = 'Keine Daten verfuegbar' if language == 'de' else 'No data available'
            story.append(Paragraph(no_data, self.styles['Normal']))

        story.append(Spacer(1, 10*mm))

        # Legend table
        legend_data = []
        for i, label in enumerate(labels):
            if data[i] > 0:
                count = data[i]
                pct = round(count / stats['total'] * 100, 1) if stats['total'] > 0 else 0
                legend_data.append([label, str(count), f"{pct}%"])

        if legend_data:
            header = ['Status', 'Anzahl', '%'] if language == 'de' else ['Status', 'Count', '%']
            legend_table = Table([header] + legend_data, colWidths=[50*mm, 25*mm, 25*mm])
            legend_table.setStyle(TableStyle([
                ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
                ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
                ('FONTSIZE', (0, 0), (-1, -1), 10),
                ('BACKGROUND', (0, 0), (-1, 0), COLORS['light']),
                ('ALIGN', (1, 0), (-1, -1), 'RIGHT'),
                ('BOTTOMPADDING', (0, 0), (-1, -1), 5),
                ('TOPPADDING', (0, 0), (-1, -1), 5),
                ('GRID', (0, 0), (-1, -1), 0.5, COLORS['muted']),
            ]))
            story.append(legend_table)

        return story

    def _build_checklist_section(
        self,
        session: AuditSessionDB,
        requirements: List[RequirementDB],
        signoff_map: Dict[str, AuditSignOffDB],
        language: str,
    ) -> List:
        """Build the detailed checklist section."""
        story = []

        story.append(PageBreak())
        title = 'PRUEFUNGSCHECKLISTE' if language == 'de' else 'AUDIT CHECKLIST'
        story.append(Paragraph(title, self.styles['Heading1']))

        # Group by regulation
        by_regulation = {}
        for req in requirements:
            reg_code = req.regulation.code if req.regulation else 'OTHER'
            if reg_code not in by_regulation:
                by_regulation[reg_code] = []
            by_regulation[reg_code].append(req)

        result_labels = {
            'de': {
                'compliant': 'Konform',
                'compliant_notes': 'Konform (Anm.)',
                'non_compliant': 'Nicht konform',
                'not_applicable': 'N/A',
                'pending': 'Ausstehend',
            },
            'en': {
                'compliant': 'Compliant',
                'compliant_notes': 'Compliant (Notes)',
                'non_compliant': 'Non-Compliant',
                'not_applicable': 'N/A',
                'pending': 'Pending',
            },
        }
        labels = result_labels.get(language, result_labels['de'])

        for reg_code, reqs in sorted(by_regulation.items()):
            story.append(Paragraph(reg_code, self.styles['Heading2']))

            # Build table data
            header = ['Art.', 'Titel', 'Ergebnis', 'Signiert'] if language == 'de' else \
                     ['Art.', 'Title', 'Result', 'Signed']
            table_data = [header]

            for req in reqs:
                signoff = signoff_map.get(req.id)
                result = signoff.result.value if signoff else 'pending'
                result_label = labels.get(result, result)
                signed = 'Ja' if (signoff and signoff.signature_hash) else '-'
                if language == 'en':
                    signed = 'Yes' if (signoff and signoff.signature_hash) else '-'

                # Truncate title if too long
                title_text = req.title[:50] + '...' if len(req.title) > 50 else req.title

                table_data.append([
                    req.article or '-',
                    title_text,
                    result_label,
                    signed,
                ])

            table = Table(table_data, colWidths=[20*mm, 80*mm, 35*mm, 20*mm])

            # Style rows based on result
            style_commands = [
                ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
                ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
                ('FONTSIZE', (0, 0), (-1, -1), 9),
                ('BACKGROUND', (0, 0), (-1, 0), COLORS['light']),
                ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
                ('ALIGN', (2, 0), (3, -1), 'CENTER'),
                ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
                ('TOPPADDING', (0, 0), (-1, -1), 4),
                ('GRID', (0, 0), (-1, -1), 0.5, COLORS['muted']),
                ('VALIGN', (0, 0), (-1, -1), 'TOP'),
            ]

            # Color code results
            for i, req in enumerate(reqs, start=1):
                signoff = signoff_map.get(req.id)
                if signoff:
                    result = signoff.result.value
                    if result == 'compliant':
                        style_commands.append(('TEXTCOLOR', (2, i), (2, i), COLORS['success']))
                    elif result == 'compliant_notes':
                        style_commands.append(('TEXTCOLOR', (2, i), (2, i), colors.HexColor('#2f855a')))
                    elif result == 'non_compliant':
                        style_commands.append(('TEXTCOLOR', (2, i), (2, i), COLORS['danger']))
                else:
                    style_commands.append(('TEXTCOLOR', (2, i), (2, i), COLORS['warning']))

            table.setStyle(TableStyle(style_commands))
            story.append(table)
            story.append(Spacer(1, 5*mm))

        return story

    def _build_non_compliant_appendix(
        self,
        non_compliant: List[AuditSignOffDB],
        requirements: List[RequirementDB],
        language: str,
    ) -> List:
        """Build appendix with non-compliant items detail."""
        story = []

        title = 'ANHANG: NICHT KONFORME ANFORDERUNGEN' if language == 'de' else \
                'APPENDIX: NON-COMPLIANT REQUIREMENTS'
        story.append(Paragraph(title, self.styles['Heading1']))

        req_map = {r.id: r for r in requirements}

        for i, signoff in enumerate(non_compliant, start=1):
            req = req_map.get(signoff.requirement_id)
            if not req:
                continue

            # Requirement header
            story.append(Paragraph(
                f"<b>{i}. {req.regulation.code if req.regulation else ''} {req.article}</b>",
                self.styles['Heading3']
            ))

            story.append(Paragraph(f"<b>{req.title}</b>", self.styles['Normal']))

            if req.description:
                desc = req.description[:500] + '...' if len(req.description) > 500 else req.description
                story.append(Paragraph(desc, self.styles['Small']))

            # Notes from auditor
            if signoff.notes:
                notes_label = 'Auditor-Anmerkungen' if language == 'de' else 'Auditor Notes'
                story.append(Paragraph(f"<b>{notes_label}:</b>", self.styles['Normal']))
                story.append(Paragraph(signoff.notes, self.styles['Normal']))

            story.append(Spacer(1, 5*mm))

        return story

    def _build_signature_section(
        self,
        signed_items: List[AuditSignOffDB],
        language: str,
    ) -> List:
        """Build section with digital signature verification."""
        story = []

        title = 'DIGITALE SIGNATUREN' if language == 'de' else 'DIGITAL SIGNATURES'
        story.append(Paragraph(title, self.styles['Heading1']))

        explanation = (
            'Die folgenden Pruefpunkte wurden digital signiert. '
            'Die SHA-256 Hashes dienen als unveraenderlicher Nachweis des Pruefergebnisses.'
        ) if language == 'de' else (
            'The following audit items have been digitally signed. '
            'The SHA-256 hashes serve as immutable proof of the audit result.'
        )
        story.append(Paragraph(explanation, self.styles['Normal']))
        story.append(Spacer(1, 5*mm))

        header = ['Anforderung', 'Signiert von', 'Datum', 'SHA-256 (gekuerzt)'] if language == 'de' else \
                 ['Requirement', 'Signed by', 'Date', 'SHA-256 (truncated)']

        table_data = [header]
        for item in signed_items[:50]:  # Limit to 50 entries
            table_data.append([
                item.requirement_id[:8] + '...',
                item.signed_by or '-',
                item.signed_at.strftime('%d.%m.%Y') if item.signed_at else '-',
                item.signature_hash[:16] + '...' if item.signature_hash else '-',
            ])

        table = Table(table_data, colWidths=[35*mm, 40*mm, 30*mm, 50*mm])
        table.setStyle(TableStyle([
            ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
            ('FONTNAME', (0, 1), (-1, -1), 'Courier'),
            ('FONTSIZE', (0, 0), (-1, -1), 8),
            ('BACKGROUND', (0, 0), (-1, 0), COLORS['light']),
            ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 3),
            ('TOPPADDING', (0, 0), (-1, -1), 3),
            ('GRID', (0, 0), (-1, -1), 0.5, COLORS['muted']),
        ]))

        story.append(table)

        return story
