"""Plugin manifest schema (Pydantic v2)."""

from __future__ import annotations

from typing import Any

from pydantic import BaseModel, Field, field_validator


class PluginRouteDef(BaseModel):
    """Route definition within a plugin manifest."""

    path: str = Field(..., description="URL path prefix, e.g. /api/v1/plugin-mail")
    module: str = Field(..., description="Dotted path to the module containing the APIRouter")
    router_attr: str = Field(
        default="router", description="Attribute name of the APIRouter in the module"
    )


class FieldDefinition(BaseModel):
    """Field definition for field-level permissions."""

    module: str = Field(..., description="Module name (e.g. 'companies', 'contacts')")
    field: str = Field(..., description="Field name (e.g. 'annual_revenue')")
    label: str = Field(..., description="Human-readable label")
    sensitivity: str = Field(default="normal", description="normal|sensitive|critical")


# ── Frontend UI definition models (Phase 3) ──────────────────────────────────


class FrontendMenuItem(BaseModel):
    """A sidebar navigation item contributed by a plugin."""

    label_key: str = Field(..., description="i18n key for the menu label")
    label: str = Field(default="", description="Fallback label if i18n key is missing")
    path: str = Field(..., description="Frontend route path, e.g. /mail")
    icon: str = Field(default="FileText", description="lucide-react icon name")
    group: str = Field(default="", description="Optional group label_key for tree-style nesting")
    order: int = Field(default=100, description="Sort order within the sidebar")
    badge_key: str = Field(default="", description="Optional store key for badge count")


class FrontendPageRoute(BaseModel):
    """A frontend page route contributed by a plugin."""

    path: str = Field(..., description="Frontend route path, e.g. /mail or /mail/settings")
    component: str = Field(
        ..., description="Dotted path to the React component, e.g. @/pages/Mail"
    )
    parent: str = Field(
        default="",
        description="Parent route path for nested routes (e.g. /settings for a settings sub-page)",
    )
    protected: bool = Field(default=True, description="Whether the route requires authentication")
    order: int = Field(default=100, description="Sort order")


class FrontendDetailTab(BaseModel):
    """A detail tab contributed by a plugin for entity detail views."""

    entity_type: str = Field(..., description="Entity type this tab applies to, e.g. 'contact'")
    label_key: str = Field(..., description="i18n key for the tab label")
    label: str = Field(default="", description="Fallback label")
    component: str = Field(..., description="Dotted path to the React component")
    icon: str = Field(default="FileText", description="lucide-react icon name")
    order: int = Field(default=100, description="Sort order within the detail view")
    permission: str = Field(default="", description="Optional permission required to see this tab")


class FrontendSettingsPage(BaseModel):
    """A settings sub-page contributed by a plugin."""

    path: str = Field(..., description="Settings sub-route path, e.g. mail or notifications")
    label_key: str = Field(..., description="i18n key for the settings nav label")
    label: str = Field(default="", description="Fallback label")
    component: str = Field(..., description="Dotted path to the React component")
    icon: str = Field(default="Settings", description="lucide-react icon name")
    order: int = Field(default=100, description="Sort order within settings nav")
    permission: str = Field(default="", description="Optional permission required")


class AgentDefinitionContribution(BaseModel):
    """An agent definition contributed by a plugin manifest."""

    name: str = Field(..., min_length=1, max_length=120)
    description: str = Field(default="", max_length=500)
    llm_model: str = Field(default="ollama/deepseek-v4-flash", max_length=100)
    system_prompt: str = Field(default="")
    tool_ids: list[str] = Field(default_factory=list)
    heartbeat_interval_seconds: int = Field(default=0, ge=0)
    mode: str = Field(default="reactive", pattern="^(proactive|reactive)$")
    max_executions_per_hour: int = Field(default=10, ge=1, le=1000)
    max_duration_seconds: int = Field(default=300, ge=1, le=86400)
    budget_limit_usd: float = Field(default=1.0, ge=0.0, le=10000.0)


class AutomationTemplateContribution(BaseModel):
    """An automation template contributed by a plugin manifest."""

    name: str = Field(..., min_length=1, max_length=120)
    description: str = Field(default="", max_length=500)
    trigger_type: str = Field(default="event", pattern="^(event|schedule|manual)$")
    trigger_config: dict = Field(default_factory=dict)
    conditions: list[dict] = Field(default_factory=list)
    actions: list[dict] = Field(default_factory=list)


class CronJobContribution(BaseModel):
    """A cron job contributed by a plugin manifest."""

    name: str = Field(..., min_length=1, max_length=120)
    cron_expression: str = Field(..., min_length=1, max_length=100)
    job_type: str = Field(..., pattern="^(agent_heartbeat|automation_trigger|custom)$")
    target_name: str = Field(default="", description="Reference agent/automation by name")
    plugin_name: str = Field(default="")


class HeartbeatConfigContribution(BaseModel):
    """A heartbeat config contributed by a plugin manifest."""

    agent_name: str = Field(..., min_length=1, max_length=120)
    interval_seconds: int = Field(..., ge=1)
    target_room: str = Field(default="")


class FrontendDashboardWidget(BaseModel):
    """A dashboard widget contributed by a plugin."""

    id: str = Field(..., description="Unique widget identifier")
    label_key: str = Field(..., description="i18n key for the widget title")
    label: str = Field(default="", description="Fallback label")
    component: str = Field(..., description="Dotted path to the React component")
    icon: str = Field(default="LayoutDashboard", description="lucide-react icon name")
    order: int = Field(default=100, description="Sort order on the dashboard")
    col_span: int = Field(default=1, description="Grid column span (1-4)")
    row_span: int = Field(default=1, description="Grid row span")
    permission: str = Field(default="", description="Optional permission required")


class CustomFieldDefinition(BaseModel):
    """A custom field definition contributed by a plugin manifest."""

    name: str = Field(..., min_length=1, max_length=80, description="Unique field name (snake_case)")
    label: str = Field(default="", description="Human-readable label (fallback if i18n key missing)")
    label_key: str = Field(default="", description="i18n key for the field label")
    field_type: str = Field(
        ..., pattern="^(text|number|date|select|multiselect|boolean)$", description="Field type"
    )
    options: list[str] = Field(default_factory=list, description="Options for select/multiselect types")
    default_value: Any = Field(default=None, description="Default value for the field")
    required: bool = Field(default=False, description="Whether the field is required")
    entity: str = Field(default="contact", description="Entity type this field applies to (contact/file/etc)")


class MiniAppContribution(BaseModel):
    """A MiniApp contributed by a plugin manifest."""

    app_id: str = Field(..., min_length=1, max_length=80)
    name: str = Field(..., min_length=1, max_length=120)
    icon: str = Field(default="AppWindow")
    description: str = Field(default="")
    render_schema: dict[str, Any] = Field(default_factory=dict)


class PluginManifest(BaseModel):
    """Manifest describing a plugin's metadata, dependencies, and capabilities."""

    name: str = Field(
        ..., min_length=1, max_length=80, description="Unique plugin identifier (snake_case)"
    )
    version: str = Field(..., min_length=1, max_length=40, description="Semantic version string")
    display_name: str = Field(..., min_length=1, max_length=120)
    description: str = Field(default="", max_length=500)
    dependencies: list[str] = Field(
        default_factory=list, description="Other plugin names this plugin depends on"
    )
    routes: list[PluginRouteDef] = Field(
        default_factory=list, description="Route definitions to register on activation"
    )
    events: list[str] = Field(
        default_factory=list, description="Event names this plugin listens to"
    )
    migrations: list[str] = Field(
        default_factory=list, description="Migration file names (ordered, e.g. 0001_initial.sql)"
    )
    permissions: list[str] = Field(
        default_factory=list, description="Required permissions for this plugin"
    )
    is_core: bool = Field(
        default=False, description="Whether this is a core plugin that cannot be deactivated"
    )
    field_definitions: list[FieldDefinition] = Field(
        default_factory=list, description="Field definitions for field-level permissions"
    )
    agent_capabilities: list[str] = Field(
        default_factory=list,
        description="AI agent capabilities this plugin provides (e.g. 'contact_search', 'email_draft')",
    )
    # ── Frontend UI contributions (Phase 3) ──
    menu_items: list[FrontendMenuItem] = Field(
        default_factory=list, description="Sidebar navigation items contributed by this plugin"
    )
    page_routes: list[FrontendPageRoute] = Field(
        default_factory=list, description="Frontend page routes contributed by this plugin"
    )
    detail_tabs: list[FrontendDetailTab] = Field(
        default_factory=list, description="Entity detail tabs contributed by this plugin"
    )
    settings_pages: list[FrontendSettingsPage] = Field(
        default_factory=list, description="Settings sub-pages contributed by this plugin"
    )
    dashboard_widgets: list[FrontendDashboardWidget] = Field(
        default_factory=list, description="Dashboard widgets contributed by this plugin"
    )
    # ── Plugin Contribution fields (Phase 3.5C) ──
    agent_definitions: list[AgentDefinitionContribution] = Field(
        default_factory=list, description="Agent definitions contributed by this plugin"
    )
    automation_templates: list[AutomationTemplateContribution] = Field(
        default_factory=list, description="Automation templates contributed by this plugin"
    )
    cron_jobs: list[CronJobContribution] = Field(
        default_factory=list, description="Cron jobs contributed by this plugin"
    )
    heartbeat_configs: list[HeartbeatConfigContribution] = Field(
        default_factory=list, description="Heartbeat configs contributed by this plugin"
    )
    miniapps: list[MiniAppContribution] = Field(
        default_factory=list, description="MiniApps contributed by this plugin"
    )
    custom_fields: list[CustomFieldDefinition] = Field(
        default_factory=list, description="Custom field definitions contributed by this plugin"
    )


    @field_validator("name")
    @classmethod
    def validate_name(cls, v: str) -> str:
        if not v.replace("_", "").isalnum():
            raise ValueError("Plugin name must be alphanumeric with underscores only")
        return v.lower()

    model_config = {"extra": "forbid"}


PluginManifest.model_rebuild()


class ManifestSchemaResponse(BaseModel):
    """Response model describing the manifest schema for API consumers."""

    fields: dict[str, dict[str, str]]
    example: PluginManifest


# Pre-built schema documentation for GET /api/v1/plugins/manifest endpoint
MANIFEST_SCHEMA_DOC = ManifestSchemaResponse(
    fields={
        "name": {
            "type": "str",
            "required": "true",
            "description": "Unique plugin identifier (snake_case, max 80 chars)",
        },
        "version": {"type": "str", "required": "true", "description": "Semantic version string"},
        "display_name": {
            "type": "str",
            "required": "true",
            "description": "Human-readable plugin name",
        },
        "description": {
            "type": "str",
            "required": "false",
            "description": "Plugin description (max 500 chars)",
        },
        "dependencies": {
            "type": "list[str]",
            "required": "false",
            "description": "Other plugin names required",
        },
        "routes": {
            "type": "list[PluginRouteDef]",
            "required": "false",
            "description": "Route definitions to register",
        },
        "events": {
            "type": "list[str]",
            "required": "false",
            "description": "Event names to listen to",
        },
        "migrations": {
            "type": "list[str]",
            "required": "false",
            "description": "Migration file names (ordered)",
        },
        "permissions": {
            "type": "list[str]",
            "required": "false",
            "description": "Required permissions",
        },
        "menu_items": {
            "type": "list[FrontendMenuItem]",
            "required": "false",
            "description": "Sidebar navigation items (label_key, path, icon, group, order)",
        },
        "page_routes": {
            "type": "list[FrontendPageRoute]",
            "required": "false",
            "description": "Frontend page routes (path, component, parent, protected)",
        },
        "detail_tabs": {
            "type": "list[FrontendDetailTab]",
            "required": "false",
            "description": "Entity detail tabs (entity_type, label_key, component, icon, permission)",
        },
        "settings_pages": {
            "type": "list[FrontendSettingsPage]",
            "required": "false",
            "description": "Settings sub-pages (path, label_key, component, icon, permission)",
        },
        "dashboard_widgets": {
            "type": "list[FrontendDashboardWidget]",
            "required": "false",
            "description": "Dashboard widgets (id, label_key, component, col_span, permission)",
        },
    },
    example=PluginManifest(
        name="example_plugin",
        version="1.0.0",
        display_name="Example Plugin",
        description="An example plugin demonstrating the manifest schema.",
        dependencies=[],
        routes=[],
        events=["contact.created"],
        migrations=["0001_initial.sql"],
        permissions=["contacts.read"],
        menu_items=[
            FrontendMenuItem(
                label_key="nav.examplePlugin",
                label="Example",
                path="/example",
                icon="Sparkles",
                order=50,
            )
        ],
        page_routes=[
            FrontendPageRoute(
                path="/example",
                component="@/pages/Example",
                protected=True,
            )
        ],
    ),
)


PluginManifest.model_rebuild()
