"""
PDF generation service for contract documents using WeasyPrint.
Generates legally compliant contract PDFs with audit trails.

NOTE: WeasyPrint requires system dependencies (Pango, GObject, Cairo).
To enable PDF generation, add these to the Docker image:
    apt-get install -y libpango-1.0-0 libpangoft2-1.0-0 libgobject-2.0-0 libcairo2
    pip install weasyprint
"""
import logging
from io import BytesIO
from django.template.loader import render_to_string
from django.conf import settings

logger = logging.getLogger(__name__)

try:
    from weasyprint import HTML, CSS
    from weasyprint.text.fonts import FontConfiguration
    WEASYPRINT_AVAILABLE = True
except (ImportError, OSError) as e:
    logger.warning(f"WeasyPrint not available: {e}")
    WEASYPRINT_AVAILABLE = False
    HTML = None
    CSS = None
    FontConfiguration = None


class ContractPDFService:
    """
    Service for generating contract PDFs with audit trail and legal compliance.
    """

    @staticmethod
    def generate_pdf(contract):
        """
        Generate a PDF from a signed contract.

        Args:
            contract: Contract instance (must have signature)

        Returns:
            BytesIO: PDF file as bytes

        Raises:
            ValueError: If contract is not signed or signature data is missing
            RuntimeError: If WeasyPrint is not available
        """
        if not WEASYPRINT_AVAILABLE:
            raise RuntimeError(
                "WeasyPrint is not available. Please install system dependencies: "
                "libpango-1.0-0 libpangoft2-1.0-0 libgobject-2.0-0 libcairo2, "
                "then pip install weasyprint"
            )

        if contract.status != 'SIGNED':
            raise ValueError("Contract must be signed before generating PDF")

        if not hasattr(contract, 'signature') or not contract.signature:
            raise ValueError("Contract signature data is missing")

        signature = contract.signature

        # Get tenant/business info
        from django.db import connection
        from smoothschedule.identity.core.models import Tenant

        tenant = None
        if hasattr(connection, 'tenant'):
            tenant = connection.tenant
        else:
            # Fallback - try to get tenant from schema
            try:
                tenant = Tenant.objects.get(schema_name=connection.schema_name)
            except Tenant.DoesNotExist:
                logger.warning(f"Could not find tenant for schema: {connection.schema_name}")

        # Prepare context for template
        context = {
            'contract': contract,
            'signature': signature,
            'tenant': tenant,
            'business_name': tenant.name if tenant else 'SmoothSchedule',
            'business_logo_url': tenant.logo.url if tenant and tenant.logo else None,
            'customer': contract.customer,
            'event': contract.event,
            
            # Geolocation display
            'geolocation': None,
            
            # Legal compliance text
            'esign_notice': (
                "This document is a legally binding contract executed under the "
                "U.S. Electronic Signatures in Global and National Commerce Act (ESIGN Act) "
                "and the Uniform Electronic Transactions Act (UETA). "
                "By electronically signing this document, all parties agree that such signature "
                "is the legal equivalent of their manual signature."
            ),
        }

        # Format geolocation if available
        if signature.latitude and signature.longitude:
            context['geolocation'] = f"{signature.latitude}, {signature.longitude}"

        # Render HTML from template
        html_string = render_to_string('contracts/pdf_template.html', context)

        # Configure fonts
        font_config = FontConfiguration()

        # Generate PDF
        html = HTML(string=html_string, base_url=settings.STATIC_URL or '/')
        
        # Custom CSS for better PDF rendering
        css_string = """
            @page {
                size: letter;
                margin: 1in 0.75in;
                @bottom-right {
                    content: "Page " counter(page) " of " counter(pages);
                    font-size: 9pt;
                    color: #666;
                }
            }
            body {
                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
                line-height: 1.6;
                color: #1f2937;
            }
            table {
                page-break-inside: avoid;
            }
        """
        css = CSS(string=css_string, font_config=font_config)

        # Render to PDF
        pdf_bytes = BytesIO()
        html.write_pdf(pdf_bytes, stylesheets=[css], font_config=font_config)
        pdf_bytes.seek(0)

        logger.info(f"Generated PDF for contract {contract.id} ({contract.title})")
        
        return pdf_bytes

    @staticmethod
    def save_contract_pdf(contract, storage_path=None):
        """
        Generate and save contract PDF to storage.

        Args:
            contract: Contract instance
            storage_path: Optional custom storage path

        Returns:
            str: Path where PDF was saved

        Raises:
            ValueError: If contract validation fails
            RuntimeError: If WeasyPrint is not available
        """
        from django.core.files.base import ContentFile
        from django.core.files.storage import default_storage
        import os

        # Generate PDF
        pdf_bytes = ContractPDFService.generate_pdf(contract)

        # Determine storage path
        if not storage_path:
            # Use contract signing token as filename (unique)
            filename = f"contract_{contract.signing_token}.pdf"
            storage_path = os.path.join('contracts', str(contract.customer.id), filename)

        # Save to storage
        saved_path = default_storage.save(storage_path, ContentFile(pdf_bytes.read()))
        
        # Update contract model
        contract.pdf_path = saved_path
        contract.save(update_fields=['pdf_path'])

        logger.info(f"Saved contract PDF to: {saved_path}")
        
        return saved_path

    @staticmethod
    def is_available():
        """Check if PDF generation is available."""
        return WEASYPRINT_AVAILABLE

    @staticmethod
    def generate_template_preview(template, user=None):
        """
        Generate a PDF preview from a contract template with sample data.

        Args:
            template: ContractTemplate instance
            user: Optional user requesting the preview

        Returns:
            BytesIO: PDF file as bytes

        Raises:
            RuntimeError: If WeasyPrint is not available
        """
        if not WEASYPRINT_AVAILABLE:
            raise RuntimeError(
                "WeasyPrint is not available. Please install system dependencies."
            )

        from django.db import connection
        from django.utils import timezone
        from smoothschedule.identity.core.models import Tenant

        # Get tenant info
        tenant = None
        try:
            tenant = Tenant.objects.get(schema_name=connection.schema_name)
        except Tenant.DoesNotExist:
            logger.warning(f"Could not find tenant for schema: {connection.schema_name}")

        # Sample data for variable substitution
        sample_context = {
            "CUSTOMER_NAME": "John Smith",
            "CUSTOMER_FIRST_NAME": "John",
            "CUSTOMER_LAST_NAME": "Smith",
            "CUSTOMER_EMAIL": "john.smith@example.com",
            "CUSTOMER_PHONE": "(555) 123-4567",
            "BUSINESS_NAME": tenant.name if tenant else "Your Business",
            "BUSINESS_EMAIL": tenant.contact_email if tenant else "contact@example.com",
            "BUSINESS_PHONE": tenant.phone if tenant else "(555) 000-0000",
            "DATE": timezone.now().strftime("%B %d, %Y"),
            "YEAR": timezone.now().strftime("%Y"),
            "APPOINTMENT_DATE": timezone.now().strftime("%B %d, %Y"),
            "APPOINTMENT_TIME": "10:00 AM",
            "SERVICE_NAME": "Sample Service",
        }

        # Substitute variables in content
        content = template.content
        for key, value in sample_context.items():
            content = content.replace(f"{{{{{key}}}}}", str(value or ""))

        # Prepare context for template
        context = {
            'template': template,
            'content_html': content,
            'tenant': tenant,
            'business_name': tenant.name if tenant else 'SmoothSchedule',
            'business_logo_url': tenant.logo.url if tenant and tenant.logo else None,
            'is_preview': True,
            'preview_notice': 'PREVIEW - This is a sample preview with placeholder data',
        }

        # Render HTML from template
        html_string = render_to_string('contracts/pdf_preview_template.html', context)

        # Configure fonts
        font_config = FontConfiguration()

        # Generate PDF
        html = HTML(string=html_string, base_url=settings.STATIC_URL or '/')

        # Custom CSS for PDF rendering
        css_string = """
            @page {
                size: letter;
                margin: 1in 0.75in;
                @bottom-right {
                    content: "Page " counter(page) " of " counter(pages);
                    font-size: 9pt;
                    color: #666;
                }
            }
            body {
                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
                line-height: 1.6;
                color: #1f2937;
            }
            .preview-banner {
                background: #fef3c7;
                border: 2px solid #f59e0b;
                color: #92400e;
                padding: 12px;
                text-align: center;
                font-weight: bold;
                margin-bottom: 24px;
                border-radius: 4px;
            }
        """
        css = CSS(string=css_string, font_config=font_config)

        # Render to PDF
        pdf_bytes = BytesIO()
        html.write_pdf(pdf_bytes, stylesheets=[css], font_config=font_config)
        pdf_bytes.seek(0)

        logger.info(f"Generated preview PDF for template {template.id} ({template.name})")

        return pdf_bytes

    @staticmethod
    def generate_audit_certificate(contract):
        """
        Generate an audit certificate PDF for a signed contract.

        Args:
            contract: Contract instance (must have signature)

        Returns:
            BytesIO: PDF file as bytes

        Raises:
            ValueError: If contract is not signed
            RuntimeError: If WeasyPrint is not available
        """
        if not WEASYPRINT_AVAILABLE:
            raise RuntimeError(
                "WeasyPrint is not available. Please install system dependencies."
            )

        if contract.status != 'SIGNED':
            raise ValueError("Contract must be signed to generate audit certificate")

        if not hasattr(contract, 'signature') or not contract.signature:
            raise ValueError("Contract signature data is missing")

        import hashlib
        from django.db import connection
        from django.utils import timezone
        from smoothschedule.identity.core.models import Tenant

        signature = contract.signature

        # Get tenant/business info
        tenant = None
        try:
            tenant = Tenant.objects.get(schema_name=connection.schema_name)
        except Tenant.DoesNotExist:
            logger.warning(f"Could not find tenant for schema: {connection.schema_name}")

        # Calculate current hash for verification
        current_hash = hashlib.sha256(contract.content_html.encode()).hexdigest()
        hash_verified = (current_hash == signature.document_hash_at_signing)

        # Prepare context
        context = {
            'contract': contract,
            'signature': signature,
            'business_name': tenant.name if tenant else 'SmoothSchedule',
            'current_hash': current_hash,
            'hash_verified': hash_verified,
            'generated_at': timezone.now(),
        }

        # Render HTML from template
        html_string = render_to_string('contracts/audit_certificate.html', context)

        # Configure fonts
        font_config = FontConfiguration()

        # Generate PDF
        html = HTML(string=html_string, base_url=settings.STATIC_URL or '/')

        css_string = """
            @page {
                size: letter;
                margin: 0.75in;
            }
            body {
                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            }
        """
        css = CSS(string=css_string, font_config=font_config)

        pdf_bytes = BytesIO()
        html.write_pdf(pdf_bytes, stylesheets=[css], font_config=font_config)
        pdf_bytes.seek(0)

        logger.info(f"Generated audit certificate for contract {contract.id}")

        return pdf_bytes

    @staticmethod
    def generate_legal_export_package(contract):
        """
        Generate a complete legal export package as a ZIP file.

        Contains:
        - signed_contract.pdf - The signed contract document
        - audit_certificate.pdf - Official audit trail certificate
        - signature_record.json - Machine-readable audit data
        - integrity_verification.txt - Hash verification report

        Args:
            contract: Contract instance (must be signed)

        Returns:
            BytesIO: ZIP file as bytes

        Raises:
            ValueError: If contract is not signed
            RuntimeError: If WeasyPrint is not available
        """
        import zipfile
        import json
        import hashlib
        from django.utils import timezone
        from django.db import connection
        from smoothschedule.identity.core.models import Tenant

        if contract.status != 'SIGNED':
            raise ValueError("Contract must be signed for legal export")

        if not hasattr(contract, 'signature') or not contract.signature:
            raise ValueError("Contract signature data is missing")

        signature = contract.signature

        # Get tenant info
        tenant = None
        try:
            tenant = Tenant.objects.get(schema_name=connection.schema_name)
        except Tenant.DoesNotExist:
            pass

        # Calculate current hash
        current_hash = hashlib.sha256(contract.content_html.encode()).hexdigest()
        hash_verified = (current_hash == signature.document_hash_at_signing)

        # Create ZIP in memory
        zip_buffer = BytesIO()
        with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:

            # 1. Add signed contract PDF
            try:
                contract_pdf = ContractPDFService.generate_pdf(contract)
                zip_file.writestr('signed_contract.pdf', contract_pdf.read())
            except Exception as e:
                logger.error(f"Failed to generate contract PDF: {e}")
                # Add error note instead
                zip_file.writestr('signed_contract_error.txt',
                    f"Could not generate contract PDF: {e}")

            # 2. Add audit certificate PDF
            try:
                audit_pdf = ContractPDFService.generate_audit_certificate(contract)
                zip_file.writestr('audit_certificate.pdf', audit_pdf.read())
            except Exception as e:
                logger.error(f"Failed to generate audit certificate: {e}")
                zip_file.writestr('audit_certificate_error.txt',
                    f"Could not generate audit certificate: {e}")

            # 3. Add signature record JSON
            signature_record = {
                "export_metadata": {
                    "generated_at": timezone.now().isoformat(),
                    "export_type": "legal_compliance_package",
                    "format_version": "1.0",
                },
                "contract": {
                    "id": str(contract.id),
                    "title": contract.title,
                    "signing_token": str(contract.signing_token),
                    "template_name": contract.template.name if contract.template else None,
                    "template_version": contract.template_version,
                    "status": contract.status,
                    "created_at": contract.created_at.isoformat(),
                    "sent_at": contract.sent_at.isoformat() if contract.sent_at else None,
                    "expires_at": contract.expires_at.isoformat() if contract.expires_at else None,
                },
                "business": {
                    "name": tenant.name if tenant else None,
                    "subdomain": tenant.subdomain if tenant else None,
                },
                "customer": {
                    "id": contract.customer.id,
                    "name": contract.customer.get_full_name() or contract.customer.email,
                    "email": contract.customer.email,
                },
                "signature": {
                    "signer_name": signature.signer_name,
                    "signer_email": signature.signer_email,
                    "signed_at": signature.signed_at.isoformat(),
                    "ip_address": signature.ip_address,
                    "user_agent": signature.user_agent,
                    "latitude": str(signature.latitude) if signature.latitude else None,
                    "longitude": str(signature.longitude) if signature.longitude else None,
                    "consent_checkbox_checked": signature.consent_checkbox_checked,
                    "consent_text": signature.consent_text,
                    "electronic_consent_given": signature.electronic_consent_given,
                    "electronic_consent_text": signature.electronic_consent_text,
                    "document_hash_at_signing": signature.document_hash_at_signing,
                },
                "event": {
                    "id": contract.event.id if contract.event else None,
                    "service_name": contract.event.service.name if contract.event and contract.event.service else None,
                    "start_time": contract.event.start_time.isoformat() if contract.event else None,
                } if contract.event else None,
                "integrity": {
                    "hash_at_signing": signature.document_hash_at_signing,
                    "current_hash": current_hash,
                    "verified": hash_verified,
                    "algorithm": "SHA-256",
                },
            }
            zip_file.writestr('signature_record.json',
                json.dumps(signature_record, indent=2))

            # 4. Add integrity verification report
            verification_report = f"""
DOCUMENT INTEGRITY VERIFICATION REPORT
======================================
Generated: {timezone.now().strftime('%Y-%m-%d %H:%M:%S %Z')}

Contract Information
--------------------
Contract ID: {contract.id}
Contract Title: {contract.title}
Signing Token: {contract.signing_token}

Hash Verification
-----------------
Algorithm: SHA-256
Hash at Time of Signing: {signature.document_hash_at_signing}
Current Document Hash:   {current_hash}

Verification Result: {'VERIFIED - Document integrity confirmed' if hash_verified else 'MISMATCH - Document may have been modified'}

{'The document content has not been altered since the signature was applied.' if hash_verified else 'WARNING: The current document hash does not match the hash recorded at signing. This may indicate the document has been modified after signing.'}

Signature Details
-----------------
Signer Name: {signature.signer_name}
Signer Email: {signature.signer_email}
Date/Time: {signature.signed_at.strftime('%Y-%m-%d %H:%M:%S %Z')}
IP Address: {signature.ip_address}
Geolocation: {f'{signature.latitude}, {signature.longitude}' if signature.latitude else 'Not captured'}

Legal Compliance
----------------
This electronic signature complies with:
- Electronic Signatures in Global and National Commerce Act (ESIGN Act, 15 U.S.C. section 7001 et seq.)
- Uniform Electronic Transactions Act (UETA)

The signer acknowledged and accepted the terms electronically, with explicit consent to
conduct business electronically. All audit trail data has been preserved.
"""
            zip_file.writestr('integrity_verification.txt', verification_report.strip())

            # 5. Add README
            readme = f"""
LEGAL EXPORT PACKAGE
====================

This package contains the complete audit trail and supporting documentation
for the electronically signed contract.

Contents:
---------
1. signed_contract.pdf      - The complete signed contract document
2. audit_certificate.pdf    - Official audit certificate with signature details
3. signature_record.json    - Machine-readable data for automated processing
4. integrity_verification.txt - Document hash verification report

Package Details:
----------------
Contract: {contract.title}
Customer: {contract.customer.get_full_name() or contract.customer.email}
Signed: {signature.signed_at.strftime('%Y-%m-%d %H:%M:%S')}
Generated: {timezone.now().strftime('%Y-%m-%d %H:%M:%S')}

This package is intended for legal and compliance purposes, including
use as evidence in legal proceedings.

For questions, contact {tenant.name if tenant else 'the business'}.
"""
            zip_file.writestr('README.txt', readme.strip())

        zip_buffer.seek(0)
        logger.info(f"Generated legal export package for contract {contract.id}")

        return zip_buffer
