"""Scheduled Job manager for handling scheduled jobs operations."""

from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union

from ..types import (
    CronExecutionConfig,
    CronJobFrequency,
    CronJobStatus,
    CronNotificationConfig,
    CronRetryConfig,
    CronSchedule,
    ListResponse,
    Priority,
    ScheduledJob,
)

if TYPE_CHECKING:
    from ..client import ToothFairyClient


class ScheduledJobManager:
    """Manager for scheduled jobs (cron jobs) operations.

    This manager provides methods to create, update, and manage scheduled jobs.

    Example:
        >>> client = ToothFairyClient(api_key="...", workspace_id="...")
        >>> scheduled_job = client.scheduled_jobs.create(
        ...     name="Daily Report",
        ...     agent_id="agent-123",
        ...     schedule={"frequency": "DAILY", "hour": 9, "minute": 0},
        ...     timezone="UTC",
        ... )
    """

    def __init__(self, client: "ToothFairyClient"):
        """Initialize the ScheduledJobManager.

        Args:
            client: The ToothFairyClient instance.
        """
        self._client = client

    def create(
        self,
        name: str,
        agent_id: str,
        custom_prompt_id: str,
        timezone: str = "UTC",
        description: Optional[str] = None,
        forced_prompt: Optional[str] = None,
        schedule: Optional[Union[CronSchedule, Dict[str, Any]]] = None,
        frequency: Optional[CronJobFrequency] = None,
        interval: Optional[int] = None,
        cron_expression: Optional[str] = None,
        day_of_week: Optional[int] = None,
        day_of_month: Optional[int] = None,
        hour: Optional[int] = None,
        minute: Optional[int] = None,
        is_active: bool = True,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        execution_config: Optional[Union[CronExecutionConfig, Dict[str, Any]]] = None,
        notification_config: Optional[Union[CronNotificationConfig, Dict[str, Any]]] = None,
        retry_config: Optional[Union[CronRetryConfig, Dict[str, Any]]] = None,
        metadata: Optional[Dict[str, Any]] = None,
    ) -> ScheduledJob:
        """Create a new scheduled job.

        Args:
            name: Job name.
            agent_id: ID of the agent to run (required).
            custom_prompt_id: ID of custom prompt to use (required).
            timezone: Timezone for the schedule (default: UTC).
            description: Job description.
            forced_prompt: Forced prompt text.
            schedule: Complete CronSchedule object or dict.
            frequency: Schedule frequency (MINUTES, HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY, CUSTOM).
            interval: Interval for frequency (e.g., every 2 hours).
            cron_expression: Custom cron expression (for CUSTOM frequency).
            day_of_week: Day of week (0-6, 0=Sunday).
            day_of_month: Day of month (1-31).
            hour: Hour (0-23).
            minute: Minute (0-59).
            is_active: Whether the job is active.
            start_date: Start date for the job (AWSDateTime).
            end_date: End date for the job (AWSDateTime).
            execution_config: Execution configuration object or dict.
            notification_config: Notification configuration object or dict.
            retry_config: Retry configuration object or dict.
            metadata: Additional metadata (AWSJSON).

        Returns:
            The created ScheduledJob object.
        """
        data: Dict[str, Any] = {
            "name": name,
            "agentID": agent_id,
            "customPromptID": custom_prompt_id,
            "timezone": timezone,
            "isActive": is_active,
        }

        if description is not None:
            data["description"] = description
        if forced_prompt is not None:
            data["forcedPrompt"] = forced_prompt
        if start_date is not None:
            data["startDate"] = start_date
        if end_date is not None:
            data["endDate"] = end_date
        if metadata is not None:
            data["metadata"] = metadata

        # Handle schedule - either as a complete object or built from individual params
        if schedule is not None:
            if isinstance(schedule, CronSchedule):
                schedule_dict = {
                    "frequency": schedule.frequency,
                }
                if schedule.interval is not None:
                    schedule_dict["interval"] = schedule.interval
                if schedule.cron_expression is not None:
                    schedule_dict["cronExpression"] = schedule.cron_expression
                if schedule.day_of_week is not None:
                    schedule_dict["dayOfWeek"] = schedule.day_of_week
                if schedule.day_of_month is not None:
                    schedule_dict["dayOfMonth"] = schedule.day_of_month
                if schedule.hour is not None:
                    schedule_dict["hour"] = schedule.hour
                if schedule.minute is not None:
                    schedule_dict["minute"] = schedule.minute
                if schedule.start_date is not None:
                    schedule_dict["startDate"] = schedule.start_date
                if schedule.end_date is not None:
                    schedule_dict["endDate"] = schedule.end_date
                data["schedule"] = schedule_dict
            else:
                data["schedule"] = schedule
        elif frequency is not None:
            schedule_dict: Dict[str, Any] = {"frequency": frequency}
            if interval is not None:
                schedule_dict["interval"] = interval
            if cron_expression is not None:
                schedule_dict["cronExpression"] = cron_expression
            if day_of_week is not None:
                schedule_dict["dayOfWeek"] = day_of_week
            if day_of_month is not None:
                schedule_dict["dayOfMonth"] = day_of_month
            if hour is not None:
                schedule_dict["hour"] = hour
            if minute is not None:
                schedule_dict["minute"] = minute
            data["schedule"] = schedule_dict

        # Handle execution config
        if execution_config is not None:
            if isinstance(execution_config, CronExecutionConfig):
                exec_dict = {}
                if execution_config.timeout is not None:
                    exec_dict["timeout"] = execution_config.timeout
                if execution_config.max_duration is not None:
                    exec_dict["maxDuration"] = execution_config.max_duration
                if execution_config.priority is not None:
                    exec_dict["priority"] = execution_config.priority
                if execution_config.input_parameters:
                    exec_dict["inputParameters"] = execution_config.input_parameters
                if execution_config.output_format is not None:
                    exec_dict["outputFormat"] = execution_config.output_format
                if execution_config.webhook_url is not None:
                    exec_dict["webhookUrl"] = execution_config.webhook_url
                if execution_config.webhook_headers:
                    exec_dict["webhookHeaders"] = execution_config.webhook_headers
                data["executionConfig"] = exec_dict
            else:
                data["executionConfig"] = execution_config

        # Handle notification config
        if notification_config is not None:
            if isinstance(notification_config, CronNotificationConfig):
                notif_dict = {
                    "onSuccess": notification_config.on_success,
                    "onFailure": notification_config.on_failure,
                    "onStart": notification_config.on_start,
                    "emailRecipients": notification_config.email_recipients,
                }
                if notification_config.communication_service_id is not None:
                    notif_dict["communicationServiceID"] = notification_config.communication_service_id
                data["notificationConfig"] = notif_dict
            else:
                data["notificationConfig"] = notification_config

        # Handle retry config
        if retry_config is not None:
            if isinstance(retry_config, CronRetryConfig):
                data["retryConfig"] = {
                    "maxRetries": retry_config.max_retries,
                    "retryInterval": retry_config.retry_interval,
                    "backoffMultiplier": retry_config.backoff_multiplier,
                    "maxRetryInterval": retry_config.max_retry_interval,
                }
            else:
                data["retryConfig"] = retry_config

        response = self._client.request("POST", "/scheduled_job/create", data=data)
        return ScheduledJob.from_dict(response)

    def update(
        self,
        scheduled_job_id: str,
        **kwargs: Any,
    ) -> ScheduledJob:
        """Update a scheduled_job.

        Args:
            scheduled_job_id: ID of the scheduled_job to update.
            **kwargs: Fields to update.

        Returns:
            The updated ScheduledJob object.
        """
        data: Dict[str, Any] = {"id": scheduled_job_id}
        data.update(kwargs)
        response = self._client.request("POST", "/scheduled_job/update", data=data)
        return ScheduledJob.from_dict(response)

    def delete(self, scheduled_job_id: str) -> Dict[str, bool]:
        """Delete a scheduled_job.

        Args:
            scheduled_job_id: ID of the scheduled_job to delete.

        Returns:
            A dictionary with success status.
        """
        self._client.request("DELETE", f"/scheduled_job/delete/{scheduled_job_id}")
        return {"success": True}

    def get(self, scheduled_job_id: str) -> ScheduledJob:
        """Get a scheduled_job by ID.

        Args:
            scheduled_job_id: ID of the scheduled_job to retrieve.

        Returns:
            The ScheduledJob object.
        """
        response = self._client.request("GET", f"/scheduled_job/get/{scheduled_job_id}")
        return ScheduledJob.from_dict(response)

    def list(
        self,
        limit: Optional[int] = None,
        offset: Optional[int] = None,
    ) -> ListResponse:
        """List all scheduled jobs.

        Args:
            limit: Maximum number of scheduled jobs to return.
            offset: Number of scheduled jobs to skip.

        Returns:
            A ListResponse containing the scheduled jobs.
        """
        params: Dict[str, Any] = {}
        if limit is not None:
            params["limit"] = limit
        if offset is not None:
            params["offset"] = offset

        response = self._client.request("GET", "/scheduled_job/list", params=params)

        items = []
        if isinstance(response, list):
            items = [ScheduledJob.from_dict(item) for item in response]
        elif isinstance(response, dict):
            items = [ScheduledJob.from_dict(item) for item in response.get("items", [])]

        return ListResponse(items=items)

    def get_active(self) -> List[ScheduledJob]:
        """Get all active scheduled jobs.

        Returns:
            A list of active ScheduledJob objects.
        """
        result = self.list()
        return [job for job in result.items if job.is_active]

    def get_by_status(self, status: CronJobStatus) -> List[ScheduledJob]:
        """Get scheduled jobs by status.

        Args:
            status: Status to filter by (ACTIVE, PAUSED, DISABLED, RUNNING, COMPLETED, FAILED, PENDING).

        Returns:
            A list of ScheduledJob objects with the specified status.
        """
        result = self.list()
        return [job for job in result.items if job.status == status]

    def get_by_agent(self, agent_id: str) -> List[ScheduledJob]:
        """Get scheduled jobs by agent ID.

        Args:
            agent_id: ID of the agent to filter by.

        Returns:
            A list of ScheduledJob objects for the specified agent.
        """
        result = self.list()
        return [job for job in result.items if job.agent_id == agent_id]

    def pause(self, scheduled_job_id: str) -> ScheduledJob:
        """Pause a scheduled job.

        Args:
            scheduled_job_id: ID of the scheduled job to pause.

        Returns:
            The updated ScheduledJob object.
        """
        return self.update(scheduled_job_id, isActive=False, status="PAUSED")

    def resume(self, scheduled_job_id: str) -> ScheduledJob:
        """Resume a paused scheduled job.

        Args:
            scheduled_job_id: ID of the scheduled job to resume.

        Returns:
            The updated ScheduledJob object.
        """
        return self.update(scheduled_job_id, isActive=True, status="ACTIVE")

    def search(self, search_term: str) -> List[ScheduledJob]:
        """Search scheduled jobs by name.

        Args:
            search_term: Term to search for in job names.

        Returns:
            A list of matching ScheduledJob objects.
        """
        all_jobs = self.list()
        search_lower = search_term.lower()
        return [job for job in all_jobs.items if search_lower in job.name.lower()]
