"""
Example: Cronjob hook implementations.

This example shows how to use django-hooks with a cronjob management system.
"""

from dataclasses import dataclass, field
from datetime import datetime, timedelta
from typing import Any, Dict, Optional

from django_hooks import HookContext, HookRejectionError, HookType, register_hook


# 1. Define your hook context
@dataclass(frozen=True)
class CronjobHookContext(HookContext):
    """Context for cronjob operations."""

    job_id: str
    schedule: str  # Cron expression
    command: str
    user_id: int
    execution_id: Optional[str] = None
    params: Dict[str, Any] = field(default_factory=dict)


# 2. Create PRE hooks (validation)


def check_permissions(context: CronjobHookContext) -> bool:
    """
    PRE hook: Check if user has permission to perform operation.

    Priority: 10 (security checks run first)
    """
    required_permissions = {
        "schedule": "cronjob.schedule",
        "delete": "cronjob.delete",
        "pause": "cronjob.pause",
        "resume": "cronjob.resume",
    }

    perm = required_permissions.get(context.operation)
    if perm and not user_has_permission(context.user_id, perm):
        raise HookRejectionError(
            error_code="PERMISSION_DENIED",
            message=f"You don't have permission to {context.operation} jobs",
            details={
                "user_id": context.user_id,
                "required_permission": perm,
                "operation": context.operation,
            },
        )

    return True


def validate_cron_expression(context: CronjobHookContext) -> bool:
    """
    PRE hook: Validate cron expression format.

    Priority: 20 (validation)
    Operation: schedule
    """
    if context.operation != "schedule":
        return True

    try:
        # Validate cron expression (pseudo-code)
        parse_cron_expression(context.schedule)
        return True
    except ValueError as e:
        raise HookRejectionError(
            error_code="INVALID_CRON_EXPRESSION",
            message=f"Invalid cron expression: {str(e)}",
            details={"schedule": context.schedule, "error": str(e)},
        )


def check_daily_limit(context: CronjobHookContext) -> bool:
    """
    PRE hook: Enforce daily job scheduling limit.

    Priority: 50 (business rules)
    Operation: schedule
    """
    if context.operation != "schedule":
        return True

    # Get user's daily limit
    limit = get_user_daily_limit(context.user_id)

    # Count jobs scheduled today
    today_count = count_jobs_scheduled_today(context.user_id)

    if today_count >= limit:
        reset_time = datetime.now().replace(hour=0, minute=0, second=0) + timedelta(days=1)
        raise HookRejectionError(
            error_code="DAILY_LIMIT_EXCEEDED",
            message=f"You have exceeded your daily limit of {limit} jobs",
            details={
                "limit": limit,
                "current_count": today_count,
                "reset_at": reset_time.isoformat(),
            },
        )

    # Store count in metadata for other hooks
    context.metadata["daily_count"] = today_count
    return True


def check_concurrent_jobs(context: CronjobHookContext) -> bool:
    """
    PRE hook: Check if user has too many active jobs.

    Priority: 50 (business rules)
    """
    max_concurrent = get_max_concurrent_jobs(context.user_id)
    active_count = count_active_jobs(context.user_id)

    if context.operation == "schedule" and active_count >= max_concurrent:
        raise HookRejectionError(
            error_code="TOO_MANY_ACTIVE_JOBS",
            message=f"You have too many active jobs (max: {max_concurrent})",
            details={
                "max_concurrent": max_concurrent,
                "active_count": active_count,
            },
        )

    return True


# 3. Create POST hooks (reactions)


def audit_log(context: CronjobHookContext) -> None:
    """
    POST hook: Log all cronjob operations to audit trail.

    Priority: 100 (logging)
    Operation: * (all operations)
    """
    from django.contrib.admin.models import ADDITION, CHANGE, DELETION, LogEntry

    action_map = {
        "schedule": ADDITION,
        "execute": CHANGE,
        "pause": CHANGE,
        "resume": CHANGE,
        "delete": DELETION,
    }

    LogEntry.objects.create(
        user_id=context.user_id,
        content_type_id=get_cronjob_content_type_id(),
        object_id=context.job_id,
        object_repr=f"Job {context.job_id}",
        action_flag=action_map.get(context.operation, CHANGE),
        change_message=f"Operation: {context.operation} | Schedule: {context.schedule}",
    )


def send_notification(context: CronjobHookContext) -> None:
    """
    POST hook: Send email notification for important operations.

    Priority: 200 (notifications)
    Operation: schedule, delete
    """
    if context.operation not in ["schedule", "delete"]:
        return

    user_email = get_user_email(context.user_id)

    templates = {
        "schedule": {
            "subject": f"Job Scheduled: {context.job_id}",
            "template": "cronjob/scheduled.html",
        },
        "delete": {
            "subject": f"Job Deleted: {context.job_id}",
            "template": "cronjob/deleted.html",
        },
    }

    template_info = templates.get(context.operation)
    if template_info:
        send_email(
            to=user_email,
            subject=template_info["subject"],
            template=template_info["template"],
            context={
                "job_id": context.job_id,
                "schedule": context.schedule,
                "command": context.command,
                "operation": context.operation,
            },
        )


def update_statistics(context: CronjobHookContext) -> None:
    """
    POST hook: Update user statistics.

    Priority: 300 (statistics)
    """
    stats = get_user_stats(context.user_id)

    if context.operation == "schedule":
        stats.total_jobs_scheduled += 1
        stats.last_job_scheduled_at = datetime.now()
    elif context.operation == "execute":
        stats.total_jobs_executed += 1
        stats.last_job_executed_at = datetime.now()

    stats.save()


# 4. Register all hooks


def register_cronjob_hooks():
    """Register all cronjob hooks."""

    # PRE hooks (validation)
    register_hook(
        name="check_permissions",
        hook_type=HookType.PRE,
        callback=check_permissions,
        operation="*",  # All operations
        priority=10,
    )

    register_hook(
        name="validate_cron",
        hook_type=HookType.PRE,
        callback=validate_cron_expression,
        operation="schedule",
        priority=20,
    )

    register_hook(
        name="check_daily_limit",
        hook_type=HookType.PRE,
        callback=check_daily_limit,
        operation="schedule",
        priority=50,
    )

    register_hook(
        name="check_concurrent",
        hook_type=HookType.PRE,
        callback=check_concurrent_jobs,
        operation="schedule",
        priority=50,
    )

    # POST hooks (reactions)
    register_hook(
        name="audit_log",
        hook_type=HookType.POST,
        callback=audit_log,
        operation="*",  # All operations
        priority=100,
    )

    register_hook(
        name="send_notification",
        hook_type=HookType.POST,
        callback=send_notification,
        operation="*",  # Filtered internally
        priority=200,
    )

    register_hook(
        name="update_stats",
        hook_type=HookType.POST,
        callback=update_statistics,
        operation="*",
        priority=300,
    )


# Helper functions (pseudo-code)


def user_has_permission(user_id: int, permission: str) -> bool:
    """Check if user has permission."""
    # Your permission check logic
    return True


def get_user_daily_limit(user_id: int) -> int:
    """Get user's daily job scheduling limit."""
    # Your logic to get limit (e.g., from user tier)
    return 50


def count_jobs_scheduled_today(user_id: int) -> int:
    """Count jobs scheduled by user today."""
    # Your database query
    return 0


def get_max_concurrent_jobs(user_id: int) -> int:
    """Get max concurrent jobs for user."""
    return 10


def count_active_jobs(user_id: int) -> int:
    """Count active jobs for user."""
    return 0


def parse_cron_expression(expression: str):
    """Validate cron expression."""
    # Your validation logic
    pass


def get_cronjob_content_type_id() -> int:
    """Get Django ContentType ID for cronjob model."""
    from django.contrib.contenttypes.models import ContentType

    return ContentType.objects.get_for_model(CronjobModel).id


def get_user_email(user_id: int) -> str:
    """Get user's email address."""
    # Your user query
    return "user@example.com"


def send_email(to: str, subject: str, template: str, context: dict):
    """Send email notification."""
    # Your email sending logic
    pass


def get_user_stats(user_id: int):
    """Get user statistics object."""
    # Your stats query
    pass


# Usage example
if __name__ == "__main__":
    # Register all hooks
    register_cronjob_hooks()

    # Now your CronjobService will use these hooks
    from cronjob_service import CronjobService

    service = CronjobService(enable_hooks=True)

    result = service.schedule_job(
        job_id="backup-db",
        schedule="0 2 * * *",  # 2 AM daily
        command="/scripts/backup.sh",
        user_id=123,
    )

    if result.success:
        print(f"✓ Job scheduled: {result.job_id}")
        if result.post_hook_errors:
            print(f"⚠ POST hook warnings: {len(result.post_hook_errors)}")
    else:
        print(f"✗ Failed: {result.error_code} - {result.message}")
