from sqlalchemy.orm import Session
from typing import Optional, Dict, Any, List
from datetime import datetime
import secrets
import logging

from ..models.gdpr_compliance import (
    DataSubjectRequest,
    DataSubjectRequestType,
    DataSubjectRequestStatus,
    DataRetentionPolicy,
    ConsentRecord
)
from ...auth.models.user import User
from ...bookings.models.booking import Booking
from ...payments.models.payment import Payment
from ...reviews.models.review import Review
from ...shared.config.logging_config import get_logger

logger = get_logger(__name__)

class GDPRService:
    """Service for GDPR compliance operations"""
    
    @staticmethod
    def create_data_subject_request(
        db: Session,
        email: str,
        request_type: DataSubjectRequestType,
        description: Optional[str] = None,
        ip_address: Optional[str] = None,
        user_agent: Optional[str] = None
    ) -> DataSubjectRequest:
        """Create a new data subject request"""
        # Find user by email
        user = db.query(User).filter(User.email == email.lower()).first()
        
        # Generate verification token
        verification_token = secrets.token_urlsafe(32)
        
        request = DataSubjectRequest(
            user_id=user.id if user else None,
            email=email.lower(),
            request_type=request_type,
            status=DataSubjectRequestStatus.pending,
            description=description,
            verification_token=verification_token,
            ip_address=ip_address,
            user_agent=user_agent
        )
        
        db.add(request)
        db.commit()
        db.refresh(request)
        
        logger.info(f"Data subject request created: {request_type.value} for {email}")
        return request
    
    @staticmethod
    def verify_request(db: Session, verification_token: str) -> bool:
        """Verify a data subject request"""
        request = db.query(DataSubjectRequest).filter(
            DataSubjectRequest.verification_token == verification_token
        ).first()
        
        if not request:
            return False
        
        request.verified = True
        request.verified_at = datetime.utcnow()
        db.commit()
        
        return True
    
    @staticmethod
    def get_user_data(db: Session, user_id: int) -> Dict[str, Any]:
        """Get all data for a user (for access request)"""
        user = db.query(User).filter(User.id == user_id).first()
        if not user:
            raise ValueError("User not found")
        
        # Collect all user data
        data = {
            "user": {
                "id": user.id,
                "email": user.email,
                "full_name": user.full_name,
                "phone": user.phone,
                "created_at": user.created_at.isoformat() if user.created_at else None,
            },
            "bookings": [],
            "payments": [],
            "reviews": [],
        }
        
        # Get bookings
        bookings = db.query(Booking).filter(Booking.user_id == user_id).all()
        for booking in bookings:
            data["bookings"].append({
                "id": booking.id,
                "booking_number": booking.booking_number,
                "check_in_date": booking.check_in_date.isoformat() if booking.check_in_date else None,
                "check_out_date": booking.check_out_date.isoformat() if booking.check_out_date else None,
                "total_price": float(booking.total_price) if booking.total_price else None,
                "status": booking.status.value if hasattr(booking.status, 'value') else booking.status,
            })
        
        # Get payments
        payments = db.query(Payment).filter(Payment.booking.has(user_id=user_id)).all()
        for payment in payments:
            data["payments"].append({
                "id": payment.id,
                "amount": float(payment.amount) if payment.amount else None,
                "payment_method": payment.payment_method,
                "payment_status": payment.payment_status,
                "payment_date": payment.payment_date.isoformat() if payment.payment_date else None,
            })
        
        # Get reviews
        reviews = db.query(Review).filter(Review.user_id == user_id).all()
        for review in reviews:
            data["reviews"].append({
                "id": review.id,
                "rating": review.rating,
                "comment": review.comment,
                "created_at": review.created_at.isoformat() if review.created_at else None,
            })
        
        return data
    
    @staticmethod
    def delete_user_data(db: Session, user_id: int) -> bool:
        """Delete all user data (for erasure request)"""
        try:
            user = db.query(User).filter(User.id == user_id).first()
            if not user:
                return False
            
            # Anonymize user data instead of deleting (for audit trail)
            user.email = f"deleted_{user.id}@deleted.local"
            user.full_name = "Deleted User"
            user.phone = None
            user.password = "deleted"  # Invalidate password
            
            # Delete related data
            # Note: In production, you might want to soft-delete or anonymize instead
            db.query(Booking).filter(Booking.user_id == user_id).delete()
            db.query(Review).filter(Review.user_id == user_id).delete()
            
            db.commit()
            logger.info(f"User data deleted/anonymized for user {user_id}")
            return True
        except Exception as e:
            logger.error(f"Error deleting user data: {str(e)}")
            db.rollback()
            return False
    
    @staticmethod
    def export_user_data(db: Session, user_id: int, format: str = 'json') -> Dict[str, Any]:
        """Export user data in portable format (for portability request)
        
        Args:
            db: Database session
            user_id: User ID to export
            format: Export format ('json' or 'csv')
        
        Returns:
            Dict containing exported data or CSV string
        """
        data = GDPRService.get_user_data(db, user_id)
        
        if format.lower() == 'csv':
            import csv
            import io
            
            output = io.StringIO()
            writer = csv.writer(output)
            
            # Write user data
            writer.writerow(['Data Type', 'Field', 'Value'])
            user_data = data.get('user', {})
            for key, value in user_data.items():
                writer.writerow(['User', key, value])
            
            # Write bookings
            writer.writerow([])
            writer.writerow(['Bookings'])
            writer.writerow(['ID', 'Booking Number', 'Check In', 'Check Out', 'Total Price', 'Status'])
            for booking in data.get('bookings', []):
                writer.writerow([
                    booking.get('id'),
                    booking.get('booking_number'),
                    booking.get('check_in_date'),
                    booking.get('check_out_date'),
                    booking.get('total_price'),
                    booking.get('status')
                ])
            
            # Write payments
            writer.writerow([])
            writer.writerow(['Payments'])
            writer.writerow(['ID', 'Amount', 'Payment Method', 'Payment Status', 'Payment Date'])
            for payment in data.get('payments', []):
                writer.writerow([
                    payment.get('id'),
                    payment.get('amount'),
                    payment.get('payment_method'),
                    payment.get('payment_status'),
                    payment.get('payment_date')
                ])
            
            # Write reviews
            writer.writerow([])
            writer.writerow(['Reviews'])
            writer.writerow(['ID', 'Rating', 'Comment', 'Created At'])
            for review in data.get('reviews', []):
                writer.writerow([
                    review.get('id'),
                    review.get('rating'),
                    review.get('comment'),
                    review.get('created_at')
                ])
            
            return {'format': 'csv', 'data': output.getvalue()}
        
        return {'format': 'json', 'data': data}
    
    @staticmethod
    def record_consent(
        db: Session,
        user_id: int,
        consent_type: str,
        granted: bool,
        ip_address: Optional[str] = None,
        user_agent: Optional[str] = None,
        version: Optional[str] = None
    ) -> ConsentRecord:
        """Record user consent"""
        # Revoke previous consent if granting new one
        if granted:
            previous = db.query(ConsentRecord).filter(
                ConsentRecord.user_id == user_id,
                ConsentRecord.consent_type == consent_type,
                ConsentRecord.revoked_at.is_(None)
            ).first()
            
            if previous:
                previous.revoked_at = datetime.utcnow()
        
        consent = ConsentRecord(
            user_id=user_id,
            consent_type=consent_type,
            granted=granted,
            granted_at=datetime.utcnow() if granted else None,
            revoked_at=datetime.utcnow() if not granted else None,
            ip_address=ip_address,
            user_agent=user_agent,
            version=version
        )
        
        db.add(consent)
        db.commit()
        db.refresh(consent)
        
        return consent
    
    @staticmethod
    def check_consent(db: Session, user_id: int, consent_type: str) -> bool:
        """Check if user has granted consent"""
        consent = db.query(ConsentRecord).filter(
            ConsentRecord.user_id == user_id,
            ConsentRecord.consent_type == consent_type,
            ConsentRecord.granted == True,
            ConsentRecord.revoked_at.is_(None)
        ).order_by(ConsentRecord.granted_at.desc()).first()
        
        return consent is not None

gdpr_service = GDPRService()

