from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Callable, Protocol


class Plugin(Protocol):
    name: str
    metadata: 'PluginMetadata'

    def setup(self, window: Any) -> None: ...


@dataclass
class PluginMetadata:
    name: str
    version: str = '0.1.0'
    author: str = 'community'
    description: str = ''
    enabled: bool = True
    safe: bool = True
    settings_schema: dict[str, Any] = field(default_factory=dict)


@dataclass
class CustomWidgetSpec:
    render: Callable[[Any, Any, int], str]
    handle: Callable[[Any, Any], None] | None = None


class WidgetRegistry:
    def __init__(self) -> None:
        self.specs: dict[str, CustomWidgetSpec] = {}

    def register(self, name: str, render: Callable[[Any, Any, int], str], handle: Callable[[Any, Any], None] | None = None) -> None:
        self.specs[name] = CustomWidgetSpec(render=render, handle=handle)

    def names(self) -> list[str]:
        return sorted(self.specs)


class PluginSandbox:
    def allow(self, metadata: PluginMetadata) -> bool:
        return bool(metadata.safe)


class PluginManager:
    def __init__(self) -> None:
        self.plugins: dict[str, Any] = {}
        self.metadata: dict[str, PluginMetadata] = {}
        self.sandbox = PluginSandbox()

    def register(self, plugin: Any) -> bool:
        meta = getattr(plugin, 'metadata', PluginMetadata(name=getattr(plugin, 'name', plugin.__class__.__name__)))
        if not self.sandbox.allow(meta):
            return False
        self.plugins[meta.name] = plugin
        self.metadata[meta.name] = meta
        return True

    def enable(self, name: str) -> None:
        if name in self.metadata:
            self.metadata[name].enabled = True

    def disable(self, name: str) -> None:
        if name in self.metadata:
            self.metadata[name].enabled = False

    def enabled_plugins(self) -> list[Any]:
        return [self.plugins[name] for name, meta in self.metadata.items() if meta.enabled]

    def rows(self) -> list[list[str]]:
        rows = []
        for name, meta in sorted(self.metadata.items()):
            rows.append([name, meta.version, meta.author, 'enabled' if meta.enabled else 'disabled', 'safe' if meta.safe else 'unsafe'])
        return rows
