"""
Dynamics 365 Audit Bridge Module
Integrates with FoundryMatch audit system
"""

import logging
from typing import Dict, Any, Optional
from datetime import datetime
import json

logger = logging.getLogger(__name__)


class DynamicsAuditIntegration:
    """
    Bridge between Dynamics integration and FoundryMatch audit system
    Mirrors SalesforceAuditIntegration interface
    """

    def __init__(self, audit_logger, integration):
        """
        Initialize audit bridge

        Args:
            audit_logger: Main AuditLogger instance
            integration: DynamicsIntegration instance
        """
        self.audit_logger = audit_logger
        self.integration = integration
        self.session_id = None

    async def start_session(self, metadata: Dict[str, Any] = None) -> str:
        """Start new audit session"""
        session_metadata = {
            "integration": "dynamics365",
            "user": self.integration.credentials.client_id,
            "resource": self.integration.credentials.resource,
            "start_time": datetime.utcnow().isoformat()
        }

        if metadata:
            session_metadata.update(metadata)

        self.session_id = await self.audit_logger.start_session(
            session_type="dynamics_integration",
            metadata=session_metadata
        )

        return self.session_id

    async def end_session(self, summary: Dict[str, Any] = None):
        """End current audit session"""
        if not self.session_id:
            return

        session_summary = {
            "end_time": datetime.utcnow().isoformat(),
            "api_calls": getattr(self, "_api_call_count", 0),
            "errors": getattr(self, "_error_count", 0)
        }

        if summary:
            session_summary.update(summary)

        await self.audit_logger.end_session(self.session_id, session_summary)
        self.session_id = None

    async def log_api_call(self, method: str, endpoint: str,
                          status_code: int, duration_ms: float,
                          error: Optional[str] = None):
        """Log API call details"""
        # Track call count
        if not hasattr(self, "_api_call_count"):
            self._api_call_count = 0
        self._api_call_count += 1

        # Track errors
        if error or status_code >= 400:
            if not hasattr(self, "_error_count"):
                self._error_count = 0
            self._error_count += 1

        event_data = {
            "method": method,
            "endpoint": endpoint,
            "status_code": status_code,
            "duration_ms": duration_ms,
            "timestamp": datetime.utcnow().isoformat()
        }

        if error:
            event_data["error"] = error

        # Add rate limit info if available
        if hasattr(self.integration, "rate_limiter"):
            rate_limit_status = self.integration.rate_limiter.get_status()
            event_data["rate_limit"] = {
                "burst_remaining": rate_limit_status["burst_tokens"],
                "service_remaining": rate_limit_status["service_tokens"]
            }

        await self.audit_logger.log_event(
            event_type="dynamics_api_call",
            event_data=event_data,
            session_id=self.session_id
        )

    async def log_authentication(self, success: bool, details: Dict[str, Any]):
        """Log authentication attempts"""
        event_data = {
            "success": success,
            "timestamp": datetime.utcnow().isoformat(),
            "method": details.get("method", "oauth"),
            "client_id": details.get("client_id"),
            "tenant_id": details.get("tenant_id")
        }

        if "error" in details:
            event_data["error"] = details["error"]

        if "duration_ms" in details:
            event_data["duration_ms"] = details["duration_ms"]

        await self.audit_logger.log_event(
            event_type="dynamics_authentication",
            event_data=event_data,
            session_id=self.session_id
        )

    async def log_batch_operation(self, operation: str, total_records: int,
                                 successful: int, failed: int,
                                 duration_ms: float):
        """Log batch operation results"""
        event_data = {
            "operation": operation,
            "total_records": total_records,
            "successful": successful,
            "failed": failed,
            "duration_ms": duration_ms,
            "success_rate": (successful / total_records) if total_records > 0 else 0,
            "timestamp": datetime.utcnow().isoformat()
        }

        await self.audit_logger.log_event(
            event_type="dynamics_batch_operation",
            event_data=event_data,
            session_id=self.session_id
        )

    async def log_error(self, error_type: str, error_details: Any,
                       context: Optional[Dict[str, Any]] = None):
        """Log error details"""
        event_data = {
            "error_type": error_type,
            "timestamp": datetime.utcnow().isoformat()
        }

        # Handle different error detail types
        if isinstance(error_details, Exception):
            event_data["error_message"] = str(error_details)
            event_data["error_class"] = error_details.__class__.__name__
        elif isinstance(error_details, dict):
            event_data.update(error_details)
        else:
            event_data["error_details"] = str(error_details)

        if context:
            event_data["context"] = context

        await self.audit_logger.log_event(
            event_type="dynamics_error",
            event_data=event_data,
            session_id=self.session_id
        )

    async def log_event(self, event_name: str, event_data: Dict[str, Any]):
        """Log generic event"""
        event_data["timestamp"] = datetime.utcnow().isoformat()

        await self.audit_logger.log_event(
            event_type=f"dynamics_{event_name}",
            event_data=event_data,
            session_id=self.session_id
        )

    async def log_data_validation(self, entity: str, total_rows: int,
                                 valid_rows: int, invalid_rows: int,
                                 validation_errors: list):
        """Log data validation results"""
        event_data = {
            "entity": entity,
            "total_rows": total_rows,
            "valid_rows": valid_rows,
            "invalid_rows": invalid_rows,
            "validation_rate": (valid_rows / total_rows) if total_rows > 0 else 0,
            "error_count": len(validation_errors),
            "timestamp": datetime.utcnow().isoformat()
        }

        # Include sample of errors (first 10)
        if validation_errors:
            event_data["sample_errors"] = [
                {
                    "row": err.row_index,
                    "field": err.field,
                    "error_type": err.error_type,
                    "message": err.message
                }
                for err in validation_errors[:10]
            ]

        await self.audit_logger.log_event(
            event_type="dynamics_data_validation",
            event_data=event_data,
            session_id=self.session_id
        )

    async def log_workflow_execution(self, workflow_name: str,
                                   params: Dict[str, Any],
                                   result: Any):
        """Log workflow execution details"""
        event_data = {
            "workflow_name": workflow_name,
            "timestamp": datetime.utcnow().isoformat(),
            "params": self._sanitize_params(params),
            "status": result.status,
            "total_processed": result.total_processed,
            "successful": result.successful,
            "failed": result.failed,
            "execution_time": result.execution_time
        }

        if result.errors:
            event_data["error_count"] = len(result.errors)
            event_data["sample_errors"] = result.errors[:5]

        await self.audit_logger.log_event(
            event_type="dynamics_workflow_execution",
            event_data=event_data,
            session_id=self.session_id
        )

    def _sanitize_params(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Sanitize parameters for logging (remove sensitive data)"""
        sanitized = {}

        for key, value in params.items():
            if key in ["password", "client_secret", "access_token", "refresh_token"]:
                sanitized[key] = "***REDACTED***"
            elif isinstance(value, list) and len(value) > 100:
                # Truncate large lists
                sanitized[key] = f"<list of {len(value)} items>"
            elif isinstance(value, dict):
                # Recursively sanitize nested dicts
                sanitized[key] = self._sanitize_params(value)
            else:
                sanitized[key] = value

        return sanitized

    async def get_session_summary(self) -> Dict[str, Any]:
        """Get summary of current session"""
        if not self.session_id:
            return {}

        summary = await self.audit_logger.get_session_summary(self.session_id)

        # Add Dynamics-specific metrics
        if summary:
            events = summary.get("events", [])

            # Calculate API call metrics
            api_calls = [e for e in events if e["event_type"] == "dynamics_api_call"]
            if api_calls:
                total_duration = sum(e["event_data"].get("duration_ms", 0) for e in api_calls)
                summary["api_metrics"] = {
                    "total_calls": len(api_calls),
                    "total_duration_ms": total_duration,
                    "avg_duration_ms": total_duration / len(api_calls),
                    "error_count": sum(1 for e in api_calls if e["event_data"].get("error"))
                }

            # Calculate batch operation metrics
            batch_ops = [e for e in events if e["event_type"] == "dynamics_batch_operation"]
            if batch_ops:
                summary["batch_metrics"] = {
                    "total_operations": len(batch_ops),
                    "total_records": sum(e["event_data"]["total_records"] for e in batch_ops),
                    "total_successful": sum(e["event_data"]["successful"] for e in batch_ops),
                    "total_failed": sum(e["event_data"]["failed"] for e in batch_ops)
                }

        return summary
