"""
Admin routes for GDPR compliance management.
"""
from fastapi import APIRouter, Depends, HTTPException, Query, Body
from sqlalchemy.orm import Session
from typing import Optional, Dict, Any, List
from pydantic import BaseModel
from datetime import datetime

from ...shared.config.database import get_db
from ...shared.config.logging_config import get_logger
from ...security.middleware.auth import authorize_roles
from ...auth.models.user import User
from ..services.breach_service import breach_service
from ..services.retention_service import retention_service
from ..services.data_processing_service import data_processing_service
from ..models.data_breach import BreachType, BreachStatus
from ...shared.utils.response_helpers import success_response

logger = get_logger(__name__)
router = APIRouter(prefix='/gdpr/admin', tags=['gdpr-admin'])

# Data Breach Management

class BreachCreateRequest(BaseModel):
    breach_type: str
    description: str
    affected_data_categories: Optional[List[str]] = None
    affected_data_subjects: Optional[int] = None
    occurred_at: Optional[str] = None
    likely_consequences: Optional[str] = None
    measures_proposed: Optional[str] = None
    risk_level: Optional[str] = None

@router.post('/breaches')
async def create_breach(
    breach_data: BreachCreateRequest,
    current_user: User = Depends(authorize_roles('admin')),
    db: Session = Depends(get_db)
):
    """Create a data breach record (admin only)."""
    try:
        try:
            breach_type_enum = BreachType(breach_data.breach_type)
        except ValueError:
            raise HTTPException(status_code=400, detail=f'Invalid breach type: {breach_data.breach_type}')
        
        occurred_at = None
        if breach_data.occurred_at:
            occurred_at = datetime.fromisoformat(breach_data.occurred_at.replace('Z', '+00:00'))
        
        breach = await breach_service.create_breach(
            db=db,
            breach_type=breach_type_enum,
            description=breach_data.description,
            reported_by=current_user.id,
            affected_data_categories=breach_data.affected_data_categories,
            affected_data_subjects=breach_data.affected_data_subjects,
            occurred_at=occurred_at,
            likely_consequences=breach_data.likely_consequences,
            measures_proposed=breach_data.measures_proposed,
            risk_level=breach_data.risk_level
        )
        
        return success_response(
            data={
                'breach_id': breach.id,
                'status': breach.status.value,
                'detected_at': breach.detected_at.isoformat()
            },
            message='Data breach record created'
        )
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f'Error creating breach: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

@router.get('/breaches')
async def get_breaches(
    status: Optional[str] = Query(None),
    page: int = Query(1, ge=1),
    limit: int = Query(20, ge=1, le=100),
    current_user: User = Depends(authorize_roles('admin')),
    db: Session = Depends(get_db)
):
    """Get all data breaches (admin only)."""
    try:
        status_enum = None
        if status:
            try:
                status_enum = BreachStatus(status)
            except ValueError:
                raise HTTPException(status_code=400, detail=f'Invalid status: {status}')
        
        offset = (page - 1) * limit
        breaches = breach_service.get_breaches(
            db=db,
            status=status_enum,
            limit=limit,
            offset=offset
        )
        
        return success_response(data={
            'breaches': [{
                'id': breach.id,
                'breach_type': breach.breach_type.value,
                'status': breach.status.value,
                'description': breach.description,
                'risk_level': breach.risk_level,
                'detected_at': breach.detected_at.isoformat(),
                'reported_to_authority_at': breach.reported_to_authority_at.isoformat() if breach.reported_to_authority_at else None,
                'notified_data_subjects_at': breach.notified_data_subjects_at.isoformat() if breach.notified_data_subjects_at else None,
            } for breach in breaches]
        })
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f'Error getting breaches: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

@router.post('/breaches/{breach_id}/report-authority')
async def report_breach_to_authority(
    breach_id: int,
    authority_reference: str = Body(...),
    current_user: User = Depends(authorize_roles('admin')),
    db: Session = Depends(get_db)
):
    """Report breach to supervisory authority (admin only)."""
    try:
        breach = await breach_service.report_to_authority(
            db=db,
            breach_id=breach_id,
            authority_reference=authority_reference,
            reported_by=current_user.id
        )
        
        return success_response(
            data={
                'breach_id': breach.id,
                'authority_reference': breach.authority_reference,
                'reported_at': breach.reported_to_authority_at.isoformat()
            },
            message='Breach reported to supervisory authority'
        )
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        logger.error(f'Error reporting breach: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

@router.post('/breaches/{breach_id}/notify-subjects')
async def notify_data_subjects(
    breach_id: int,
    notification_method: str = Body(...),
    current_user: User = Depends(authorize_roles('admin')),
    db: Session = Depends(get_db)
):
    """Notify affected data subjects (admin only)."""
    try:
        breach = await breach_service.notify_data_subjects(
            db=db,
            breach_id=breach_id,
            notification_method=notification_method,
            notified_by=current_user.id
        )
        
        return success_response(
            data={
                'breach_id': breach.id,
                'notification_method': breach.notification_method,
                'notified_at': breach.notified_data_subjects_at.isoformat()
            },
            message='Data subjects notified'
        )
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        logger.error(f'Error notifying subjects: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

# Data Retention Management

class RetentionRuleCreateRequest(BaseModel):
    data_category: str
    retention_period_days: int
    retention_period_months: Optional[int] = None
    retention_period_years: Optional[int] = None
    legal_basis: Optional[str] = None
    legal_requirement: Optional[str] = None
    action_after_retention: str = 'anonymize'
    conditions: Optional[Dict[str, Any]] = None
    description: Optional[str] = None

@router.post('/retention-rules')
async def create_retention_rule(
    rule_data: RetentionRuleCreateRequest,
    current_user: User = Depends(authorize_roles('admin')),
    db: Session = Depends(get_db)
):
    """Create a data retention rule (admin only)."""
    try:
        rule = retention_service.create_retention_rule(
            db=db,
            data_category=rule_data.data_category,
            retention_period_days=rule_data.retention_period_days,
            retention_period_months=rule_data.retention_period_months,
            retention_period_years=rule_data.retention_period_years,
            legal_basis=rule_data.legal_basis,
            legal_requirement=rule_data.legal_requirement,
            action_after_retention=rule_data.action_after_retention,
            conditions=rule_data.conditions,
            description=rule_data.description,
            created_by=current_user.id
        )
        
        return success_response(
            data={
                'rule_id': rule.id,
                'data_category': rule.data_category,
                'retention_period_days': rule.retention_period_days
            },
            message='Retention rule created successfully'
        )
    except Exception as e:
        logger.error(f'Error creating retention rule: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

@router.get('/retention-rules')
async def get_retention_rules(
    is_active: Optional[bool] = Query(None),
    current_user: User = Depends(authorize_roles('admin')),
    db: Session = Depends(get_db)
):
    """Get retention rules (admin only)."""
    try:
        rules = retention_service.get_retention_rules(db=db, is_active=is_active)
        
        return success_response(data={
            'rules': [{
                'id': rule.id,
                'data_category': rule.data_category,
                'retention_period_days': rule.retention_period_days,
                'action_after_retention': rule.action_after_retention,
                'is_active': rule.is_active,
                'legal_basis': rule.legal_basis
            } for rule in rules]
        })
    except Exception as e:
        logger.error(f'Error getting retention rules: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

@router.get('/retention-logs')
async def get_retention_logs(
    data_category: Optional[str] = Query(None),
    page: int = Query(1, ge=1),
    limit: int = Query(50, ge=1, le=100),
    current_user: User = Depends(authorize_roles('admin')),
    db: Session = Depends(get_db)
):
    """Get retention action logs (admin only)."""
    try:
        offset = (page - 1) * limit
        logs = retention_service.get_retention_logs(
            db=db,
            data_category=data_category,
            limit=limit,
            offset=offset
        )
        
        return success_response(data={
            'logs': [{
                'id': log.id,
                'data_category': log.data_category,
                'action_taken': log.action_taken,
                'records_affected': log.records_affected,
                'executed_at': log.executed_at.isoformat(),
                'success': log.success
            } for log in logs]
        })
    except Exception as e:
        logger.error(f'Error getting retention logs: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

# Data Processing Records (Admin View)

@router.get('/processing-records')
async def get_all_processing_records(
    user_id: Optional[int] = Query(None),
    processing_category: Optional[str] = Query(None),
    legal_basis: Optional[str] = Query(None),
    page: int = Query(1, ge=1),
    limit: int = Query(50, ge=1, le=100),
    current_user: User = Depends(authorize_roles('admin')),
    db: Session = Depends(get_db)
):
    """Get all data processing records (admin only)."""
    try:
        from ..models.data_processing_record import ProcessingCategory, LegalBasis
        
        category_enum = None
        if processing_category:
            try:
                category_enum = ProcessingCategory(processing_category)
            except ValueError:
                raise HTTPException(status_code=400, detail=f'Invalid processing category: {processing_category}')
        
        basis_enum = None
        if legal_basis:
            try:
                basis_enum = LegalBasis(legal_basis)
            except ValueError:
                raise HTTPException(status_code=400, detail=f'Invalid legal basis: {legal_basis}')
        
        offset = (page - 1) * limit
        records = data_processing_service.get_processing_records(
            db=db,
            user_id=user_id,
            processing_category=category_enum,
            legal_basis=basis_enum,
            limit=limit,
            offset=offset
        )
        
        return success_response(data={
            'records': [{
                'id': record.id,
                'processing_category': record.processing_category.value,
                'legal_basis': record.legal_basis.value,
                'purpose': record.purpose,
                'processing_timestamp': record.processing_timestamp.isoformat(),
                'user_id': record.user_id
            } for record in records]
        })
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f'Error getting processing records: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

