"""ConsentLog model — Loi 25 audit trail.

Records every grant/revoke of user consent for: CGU, confidentiality (RPRP),
marketing communications, analytics. Required by LPRPSP art. 14 (consent
explicit and tracé) and art. 3.5 (audit trail).
"""
from datetime import datetime

from sqlalchemy.orm import validates

from src.database import db


class ConsentLog(db.Model):
    """Journal Loi 25 — traçabilité des consentements utilisateurs.

    One row per (user, consent_type, version) state change. Granting,
    revoking, and re-granting all create separate rows for the audit trail.
    """
    __tablename__ = 'consent_log'

    ALLOWED_CONSENT_TYPES = ('cgu', 'confidentialite', 'marketing', 'analytics')

    id = db.Column(db.Integer, primary_key=True)
    # nullable + ondelete=SET NULL preserves audit trail (LPRPSP art. 3.5) while
    # supporting right-to-erasure (LPRPSP art. 28.1): on user deletion, the row
    # survives with user_id=NULL — proof that consent existed without identifying
    # the data subject. Pattern matches src/models/auth_log.py and access_log.py.
    user_id = db.Column(
        db.Integer,
        db.ForeignKey('user.id', ondelete='SET NULL'),
        nullable=True,
        index=True,
    )

    # 'cgu', 'confidentialite', 'marketing', 'analytics'
    consent_type = db.Column(db.String(50), nullable=False)
    # Version of the legal text accepted. Convention: ISO date 'YYYY-MM-DD' of
    # the document revision (e.g. '2026-04-27'). B-2.9 will define the canonical
    # version constants in src/legal/__init__.py — DO NOT hardcode dates here.
    version = db.Column(db.String(20), nullable=False)

    granted = db.Column(db.Boolean, nullable=False)
    granted_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
    revoked_at = db.Column(db.DateTime, nullable=True)

    # Source IP — supports both IPv4 (15 chars) and IPv6 (45 chars)
    ip_address = db.Column(db.String(45), nullable=False)
    user_agent = db.Column(db.String(500), nullable=False)

    # Backref creates User.consent_logs
    user = db.relationship('User', backref='consent_logs')

    @validates('consent_type')
    def _validate_consent_type(self, key, value):
        if value not in self.ALLOWED_CONSENT_TYPES:
            raise ValueError(
                f"Invalid consent_type {value!r}. "
                f"Must be one of: {self.ALLOWED_CONSENT_TYPES}"
            )
        return value

    def __repr__(self):
        action = 'granted' if self.granted else 'revoked'
        return f"<ConsentLog user={self.user_id} type={self.consent_type} v={self.version} {action}>"
