"""
Contract/E-Signature models for SmoothSchedule.
Provides ESIGN Act/UETA compliant digital signatures.
"""
import hashlib
import secrets
from django.db import models
from django.utils import timezone


class ContractTemplate(models.Model):
    """
    Reusable contract template with variable substitution.
    Business-specific templates stored in tenant schema.
    """
    class Scope(models.TextChoices):
        CUSTOMER = "CUSTOMER", "Customer-Level"  # One-time per customer
        APPOINTMENT = "APPOINTMENT", "Appointment-Level"  # Per booking

    class Status(models.TextChoices):
        DRAFT = "DRAFT", "Draft"
        ACTIVE = "ACTIVE", "Active"
        ARCHIVED = "ARCHIVED", "Archived"

    # Basic info
    name = models.CharField(max_length=200)
    description = models.TextField(blank=True)

    # Contract content (HTML with {{variables}})
    content = models.TextField(help_text="Contract body with {{VARIABLE}} placeholders")

    # Scope and status
    scope = models.CharField(
        max_length=20,
        choices=Scope.choices,
        default=Scope.APPOINTMENT
    )
    status = models.CharField(
        max_length=20,
        choices=Status.choices,
        default=Status.DRAFT
    )

    # Expiration settings
    expires_after_days = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text="Days after sending before contract expires (null=never)"
    )

    # Version tracking for legal compliance
    version = models.PositiveIntegerField(default=1)
    version_notes = models.TextField(blank=True)

    # Metadata
    created_by = models.ForeignKey(
        "users.User",
        on_delete=models.SET_NULL,
        null=True,
        related_name="created_contract_templates"
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        app_label = 'contracts'
        ordering = ["name"]

    def __str__(self):
        return f"{self.name} (v{self.version})"


class ServiceContractRequirement(models.Model):
    """
    Links services to required contract templates.
    When booking a service, these contracts must be signed.
    """
    service = models.ForeignKey(
        "schedule.Service",
        on_delete=models.CASCADE,
        related_name="contract_requirements"
    )
    template = models.ForeignKey(
        ContractTemplate,
        on_delete=models.CASCADE,
        related_name="service_requirements"
    )

    # Ordering for multiple contracts
    display_order = models.PositiveIntegerField(default=0)

    # Whether this is required or optional
    is_required = models.BooleanField(default=True)

    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        app_label = 'contracts'
        ordering = ["display_order"]
        unique_together = ["service", "template"]

    def __str__(self):
        return f"{self.service.name} requires {self.template.name}"


class Contract(models.Model):
    """
    Instance of a contract sent to a customer.
    Contains the rendered content at time of sending (snapshot).
    """
    class Status(models.TextChoices):
        PENDING = "PENDING", "Pending Signature"
        SIGNED = "SIGNED", "Signed"
        EXPIRED = "EXPIRED", "Expired"
        VOIDED = "VOIDED", "Voided"

    # Source template (for reference, content is snapshotted)
    template = models.ForeignKey(
        ContractTemplate,
        on_delete=models.SET_NULL,
        null=True,
        related_name="contracts"
    )
    template_version = models.PositiveIntegerField(
        help_text="Version of template when contract was created"
    )

    # Content snapshot (frozen at creation)
    title = models.CharField(max_length=200)
    content_html = models.TextField(help_text="Rendered HTML content at time of creation")
    content_hash = models.CharField(
        max_length=64,
        help_text="SHA-256 hash of content for tamper detection"
    )

    # Customer
    customer = models.ForeignKey(
        "users.User",
        on_delete=models.CASCADE,
        related_name="contracts"
    )

    # Optional appointment link (null for customer-level contracts)
    event = models.ForeignKey(
        "schedule.Event",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="contracts"
    )

    # Status and token
    status = models.CharField(
        max_length=20,
        choices=Status.choices,
        default=Status.PENDING
    )
    signing_token = models.CharField(
        max_length=64,
        unique=True,
        help_text="Token for public signing URL"
    )

    # Expiration
    expires_at = models.DateTimeField(null=True, blank=True)

    # Metadata
    sent_by = models.ForeignKey(
        "users.User",
        on_delete=models.SET_NULL,
        null=True,
        related_name="sent_contracts"
    )
    sent_at = models.DateTimeField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    # PDF storage path (generated after signing)
    pdf_path = models.CharField(max_length=500, blank=True)

    class Meta:
        app_label = 'contracts'
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["signing_token"]),
            models.Index(fields=["customer", "status"]),
            models.Index(fields=["template", "customer"]),
        ]

    def save(self, *args, **kwargs):
        if not self.signing_token:
            self.signing_token = secrets.token_urlsafe(48)
        if not self.content_hash and self.content_html:
            self.content_hash = hashlib.sha256(self.content_html.encode()).hexdigest()
        super().save(*args, **kwargs)

    def get_signing_url(self, request=None):
        """Generate the public signing URL."""
        from django.conf import settings
        base_url = getattr(settings, "FRONTEND_URL", "")
        if not base_url and request:
            base_url = f"{request.scheme}://{request.get_host()}"
        return f"{base_url}/sign/{self.signing_token}"

    def __str__(self):
        return f"{self.title} - {self.customer.email} ({self.status})"


class ContractSignature(models.Model):
    """
    Audit trail for contract signature.
    Contains all legally required data for ESIGN Act/UETA compliance.
    """
    contract = models.OneToOneField(
        Contract,
        on_delete=models.CASCADE,
        related_name="signature"
    )

    # Signature method
    consent_checkbox_checked = models.BooleanField(default=False)
    consent_text = models.TextField(
        help_text="Exact consent language shown to signer"
    )

    # Electronic consent to conduct business electronically
    electronic_consent_given = models.BooleanField(default=False)
    electronic_consent_text = models.TextField(
        help_text="ESIGN Act consent text"
    )

    # Signer identification
    signer_name = models.CharField(max_length=200)
    signer_email = models.EmailField()

    # Audit trail (ESIGN/UETA compliance)
    signed_at = models.DateTimeField()
    ip_address = models.GenericIPAddressField()
    user_agent = models.TextField()
    browser_fingerprint = models.CharField(max_length=64, blank=True)

    # Document integrity
    document_hash_at_signing = models.CharField(
        max_length=64,
        help_text="SHA-256 hash of contract content at moment of signing"
    )

    # Geolocation (optional, if available)
    latitude = models.DecimalField(
        max_digits=9,
        decimal_places=6,
        null=True,
        blank=True
    )
    longitude = models.DecimalField(
        max_digits=9,
        decimal_places=6,
        null=True,
        blank=True
    )

    class Meta:
        app_label = 'contracts'
        indexes = [
            models.Index(fields=["signed_at"]),
        ]

    def __str__(self):
        return f"Signature by {self.signer_name} on {self.signed_at}"
