from typing import Dict, Any, List, Optional
from datetime import datetime
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, and_
import csv
import io

from ..models import AuditEvent, User

class AuditService:
    """Service for audit logging and reporting"""

    def __init__(self, db: AsyncSession):
        self.db = db

    async def log_action(
        self,
        actor: User,
        action: str,
        object_type: str,
        record_ids: List[str],
        changes: Dict[str, Any],
        investigation_id: Optional[str] = None,
        action_batch_id: Optional[str] = None,
        policy_hash: Optional[str] = None,
        justification: Optional[str] = None,
        request_ip: Optional[str] = None
    ) -> AuditEvent:
        """Log an audit event"""

        event = AuditEvent(
            actor_id=actor.id,
            actor_role=actor.role.value if hasattr(actor.role, 'value') else str(actor.role),
            actor_ip=request_ip,
            action=action,
            object_type=object_type,
            record_ids=record_ids,
            changes=changes,
            investigation_id=investigation_id,
            action_batch_id=action_batch_id,
            policy_hash=policy_hash,
            justification=justification
        )

        self.db.add(event)
        await self.db.commit()

        return event

    async def get_audit_trail(
        self,
        account_id: str,
        start_date: Optional[datetime] = None,
        end_date: Optional[datetime] = None,
        actor_id: Optional[str] = None,
        action: Optional[str] = None,
        limit: int = 100
    ) -> List[AuditEvent]:
        """Get audit trail with filters"""

        # Build query
        stmt = select(AuditEvent).join(User, AuditEvent.actor_id == User.id)

        # Add filters
        conditions = [User.account_id == account_id]

        if start_date:
            conditions.append(AuditEvent.timestamp >= start_date)
        if end_date:
            conditions.append(AuditEvent.timestamp <= end_date)
        if actor_id:
            conditions.append(AuditEvent.actor_id == actor_id)
        if action:
            conditions.append(AuditEvent.action == action)

        stmt = stmt.where(and_(*conditions)).order_by(AuditEvent.timestamp.desc()).limit(limit)

        result = await self.db.execute(stmt)
        return result.scalars().all()

    async def export_audit_csv(self, events: List[AuditEvent]) -> str:
        """Export audit events to CSV"""
        output = io.StringIO()
        writer = csv.DictWriter(output, fieldnames=[
            'timestamp', 'actor_id', 'actor_role', 'action',
            'object_type', 'record_count', 'justification'
        ])
        writer.writeheader()

        for event in events:
            writer.writerow({
                'timestamp': event.timestamp.isoformat(),
                'actor_id': event.actor_id,
                'actor_role': event.actor_role,
                'action': event.action,
                'object_type': event.object_type,
                'record_count': len(event.record_ids),
                'justification': event.justification or ''
            })

        return output.getvalue()
