"""Watcher tools for Crustdata MCP Server."""

from typing import Optional

from mcp.server.fastmcp import Context
from pydantic import BaseModel, Field, field_validator

from ..client import CrustdataAPIError, CrustdataAuthError
from ..client_factory import get_client_for_request
from ..models.common import (
    FilterOperator,
    WatcherEventType,
    WatcherStatus,
    validate_future_date,
    validate_webhook_url,
)
from ..server import AppContext, mcp


class WatcherFilter(BaseModel):
    """A filter condition for watcher subscriptions."""

    filter_type: str = Field(..., description="Type of filter (e.g., 'REGION', 'TITLE', 'INDUSTRY')")
    type: str = Field(..., description="Filter operator (e.g., 'in', '=', '!=')")
    value: str | list[str] = Field(..., description="Filter value or list of values")

    @field_validator("type")
    @classmethod
    def validate_filter_operator(cls, v: str) -> str:
        """Validate filter operator is a valid FilterOperator."""
        try:
            FilterOperator(v)
        except ValueError:
            valid_ops = [op.value for op in FilterOperator]
            raise ValueError(
                f"Invalid filter operator: '{v}'. Must be one of: {', '.join(valid_ops)}"
            )
        return v


class WatcherCreateInput(BaseModel):
    """Input parameters for creating a watcher subscription."""

    event_type_slug: str = Field(
        ...,
        description="Type of event to monitor. Valid values: 'job-posting-with-keyword-and-location', "
        "'company-watch-linkedin-posts', 'linkedin-person-post-updates'",
    )

    @field_validator("event_type_slug")
    @classmethod
    def validate_event_type_slug(cls, v: str) -> str:
        """Validate event type slug is a valid WatcherEventType."""
        try:
            WatcherEventType(v)
        except ValueError:
            valid_types = [t.value for t in WatcherEventType]
            raise ValueError(
                f"Invalid event_type_slug: '{v}'. Must be one of: {', '.join(valid_types)}"
            )
        return v

    event_filters: list[dict] = Field(
        ...,
        description="Event-specific filters. Example: "
        '[{"filter_type": "REGION", "type": "in", "value": "San Francisco"}]',
    )
    notification_endpoint: str = Field(
        ...,
        description="HTTPS URL to receive webhook notifications when events occur. Must use HTTPS protocol.",
    )
    frequency: int = Field(
        1,
        ge=1,
        description="Notification frequency in days (minimum 1 day). Default: 1",
    )
    account_filters: Optional[list[dict]] = Field(
        None,
        description="Company filters. Filter types: INDUSTRY, COMPANY_HEADCOUNT, "
        "COMPANY_HQ_COUNTRY, LAST_FUNDING_ROUND_TYPE",
    )
    lead_filters: Optional[list[dict]] = Field(
        None,
        description="Person filters. Filter types: CURRENT_TITLE, PAST_TITLE, "
        "CURRENT_COMPANY, PAST_COMPANY, REGION, etc.",
    )
    expiration_date: Optional[str] = Field(
        None,
        description="Subscription expiration date in YYYY-MM-DD format. Must be a future date.",
    )
    approximate_notification_time: Optional[int] = Field(
        None,
        ge=0,
        le=23,
        description="Hour of day (0-23, UTC) to send notifications.",
    )

    @field_validator("notification_endpoint")
    @classmethod
    def validate_notification_endpoint(cls, v: str) -> str:
        """Validate notification endpoint is HTTPS."""
        return validate_webhook_url(v)

    @field_validator("expiration_date")
    @classmethod
    def validate_expiration_date(cls, v: Optional[str]) -> Optional[str]:
        """Validate expiration date is ISO format and in the future."""
        if v is None:
            return v
        return validate_future_date(v)


@mcp.tool(
    name="crustdata_watcher_create",
    description="Create a watcher subscription to monitor events like job postings, "
    "LinkedIn posts, funding rounds, etc. Notifications are sent to your webhook endpoint. "
    "Costs 1 credit to create.",
)
async def crustdata_watcher_create(
    params: WatcherCreateInput,
    ctx: Context[None, AppContext, None],
) -> dict:
    """Create a new watcher subscription.

    Args:
        params: Watcher creation parameters.
        ctx: MCP context for logging and client access.

    Returns:
        Dictionary with subscription ID and confirmation message.
    """
    client = get_client_for_request()

    data: dict = {
        "event_type_slug": params.event_type_slug,
        "event_filters": params.event_filters,
        "notification_endpoint": params.notification_endpoint,
        "frequency": params.frequency,
    }
    if params.account_filters:
        data["account_filters"] = params.account_filters
    if params.lead_filters:
        data["lead_filters"] = params.lead_filters
    if params.expiration_date:
        data["expiration_date"] = params.expiration_date
    if params.approximate_notification_time is not None:
        data["approximate_notification_time"] = params.approximate_notification_time

    try:
        ctx.info(f"Creating watcher for event type: {params.event_type_slug}")
        result = await client.post("/watcher/watches/", data=data)
        ctx.info(f"Watcher created with ID: {result.get('id')}")
        return result

    except CrustdataAuthError as e:
        ctx.error(f"Authentication failed: {e}")
        raise
    except CrustdataAPIError as e:
        ctx.error(f"API error: {e}")
        raise


class WatcherUpdateInput(BaseModel):
    """Input parameters for updating a watcher subscription."""

    subscription_id: int = Field(..., gt=0, description="ID of the subscription to update. Must be positive.")
    status: Optional[str] = Field(
        None,
        description="New status: 'active', 'paused', or 'cancelled'",
    )
    notification_endpoint: Optional[str] = Field(
        None,
        description="New HTTPS webhook endpoint URL.",
    )
    event_filters: Optional[list[dict]] = Field(
        None,
        description="Updated event filters (only for certain subscription types).",
    )

    @field_validator("status")
    @classmethod
    def validate_status(cls, v: Optional[str]) -> Optional[str]:
        """Validate status is a valid WatcherStatus."""
        if v is None:
            return v
        try:
            WatcherStatus(v)
        except ValueError:
            valid_statuses = [s.value for s in WatcherStatus]
            raise ValueError(
                f"Invalid status: '{v}'. Must be one of: {', '.join(valid_statuses)}"
            )
        return v

    @field_validator("notification_endpoint")
    @classmethod
    def validate_notification_endpoint(cls, v: Optional[str]) -> Optional[str]:
        """Validate notification endpoint is HTTPS if provided."""
        if v is None:
            return v
        return validate_webhook_url(v)


@mcp.tool(
    name="crustdata_watcher_update",
    description="Update an existing watcher subscription. Can change status (pause/resume), "
    "update webhook endpoint, or modify filters for certain subscription types.",
)
async def crustdata_watcher_update(
    params: WatcherUpdateInput,
    ctx: Context[None, AppContext, None],
) -> dict:
    """Update an existing watcher subscription.

    Args:
        params: Watcher update parameters.
        ctx: MCP context for logging and client access.

    Returns:
        Dictionary with confirmation message.
    """
    client = get_client_for_request()

    data: dict = {}
    if params.status:
        data["status"] = params.status
    if params.notification_endpoint:
        data["notification_endpoint"] = params.notification_endpoint
    if params.event_filters:
        data["event_filters"] = params.event_filters

    if not data:
        return {"error": "At least one update field required"}

    try:
        ctx.info(f"Updating watcher {params.subscription_id}")
        result = await client.post(
            f"/watcher/watches/{params.subscription_id}/update/", data=data
        )
        ctx.info("Watcher updated successfully")
        return result

    except CrustdataAuthError as e:
        ctx.error(f"Authentication failed: {e}")
        raise
    except CrustdataAPIError as e:
        ctx.error(f"API error: {e}")
        raise


class WatcherSimulateInput(BaseModel):
    """Input parameters for simulating a watcher subscription."""

    event_type_slug: str = Field(
        ...,
        description="Type of event to simulate monitoring.",
    )
    event_filters: list[dict] = Field(
        ...,
        description="Event-specific filters for the simulation.",
    )
    notification_endpoint: str = Field(
        ...,
        description="HTTPS URL to receive test webhook notification. Must use HTTPS protocol.",
    )
    frequency: int = Field(1, ge=1, description="Simulated notification frequency in days (minimum 1 day).")

    @field_validator("event_type_slug")
    @classmethod
    def validate_event_type_slug(cls, v: str) -> str:
        """Validate event type slug is a valid WatcherEventType."""
        try:
            WatcherEventType(v)
        except ValueError:
            valid_types = [t.value for t in WatcherEventType]
            raise ValueError(
                f"Invalid event_type_slug: '{v}'. Must be one of: {', '.join(valid_types)}"
            )
        return v

    @field_validator("notification_endpoint")
    @classmethod
    def validate_notification_endpoint(cls, v: str) -> str:
        """Validate notification endpoint is HTTPS."""
        return validate_webhook_url(v)


@mcp.tool(
    name="crustdata_watcher_simulate",
    description="Simulate a watcher subscription to test your webhook endpoint. "
    "Sends a test notification without creating a persistent subscription.",
)
async def crustdata_watcher_simulate(
    params: WatcherSimulateInput,
    ctx: Context[None, AppContext, None],
) -> dict:
    """Simulate a watcher subscription for testing.

    Args:
        params: Simulation parameters.
        ctx: MCP context for logging and client access.

    Returns:
        Dictionary with simulation result and test subscription ID.
    """
    client = get_client_for_request()

    data = {
        "event_type_slug": params.event_type_slug,
        "event_filters": params.event_filters,
        "notification_endpoint": params.notification_endpoint,
        "frequency": params.frequency,
    }

    try:
        ctx.info(f"Simulating watcher for: {params.event_type_slug}")
        result = await client.post("/watcher/simulation/watches/", data=data)
        ctx.info("Watcher simulation completed")
        return result

    except CrustdataAuthError as e:
        ctx.error(f"Authentication failed: {e}")
        raise
    except CrustdataAPIError as e:
        ctx.error(f"API error: {e}")
        raise


@mcp.tool(
    name="crustdata_watcher_list",
    description="List all your watcher subscriptions with their current status.",
)
async def crustdata_watcher_list(
    ctx: Context[None, AppContext, None],
) -> list[dict]:
    """List all watcher subscriptions.

    Args:
        ctx: MCP context for logging and client access.

    Returns:
        List of subscription objects with status and configuration.
    """
    client = get_client_for_request()

    try:
        ctx.info("Listing watcher subscriptions")
        result = await client.get("/watcher/watches/")

        if isinstance(result, list):
            ctx.info(f"Found {len(result)} subscriptions")
            return result
        else:
            return result.get("subscriptions", [])

    except CrustdataAuthError as e:
        ctx.error(f"Authentication failed: {e}")
        raise
    except CrustdataAPIError as e:
        ctx.error(f"API error: {e}")
        raise
