"""Signal processor — converts pending signals into commons memories."""

from __future__ import annotations

import json
import logging
from datetime import datetime
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    from chicory.orchestrator.orchestrator import Orchestrator

logger = logging.getLogger(__name__)


class SignalProcessor:
    """Reads pending signals and converts them to commons memories.

    Each signal becomes a Chicory memory with dual tags:
    project-namespaced (e.g. "chicory:auth") and shared (e.g. "auth"),
    letting the commons build its own tensor network from cross-project activity.
    """

    def __init__(self, orchestrator: Orchestrator) -> None:
        self._orchestrator = orchestrator
        self._db = orchestrator.db
        self._last_process_time: datetime | None = None

    def process_pending(self, batch_size: int = 50) -> dict[str, Any]:
        """Process up to batch_size pending signals.

        Returns stats dict with counts.
        """
        table_exists = self._db.execute(
            "SELECT name FROM sqlite_master WHERE type='table' AND name='pending_signals'"
        ).fetchone()
        if not table_exists:
            return {"processed": 0, "status": "no_signals_table"}

        rows = self._db.execute(
            """
            SELECT id, project_id, op_type, tags, strength, event_type, created_at
            FROM pending_signals
            WHERE processed = 0
            ORDER BY created_at ASC
            LIMIT ?
            """,
            (batch_size,),
        ).fetchall()

        if not rows:
            return {"processed": 0, "status": "no_pending"}

        processed = 0
        new_memory_ids: list[str] = []

        for row in rows:
            project_id = row["project_id"]
            op_type = row["op_type"]
            tags = json.loads(row["tags"])
            strength = row["strength"]
            event_type = row["event_type"]

            # Build content
            if op_type == "synchronicity":
                content = (
                    f"[{op_type}:{event_type}] Project '{project_id}' "
                    f"-- tags: {', '.join(tags)} "
                    f"(strength: {strength:.2f})"
                )
            else:
                content = (
                    f"[{op_type}] Project '{project_id}' "
                    f"-- tags: {', '.join(tags)}"
                )

            commons_tags = _build_commons_tags(
                project_id, op_type, tags, event_type
            )

            importance = 0.5
            if op_type == "synchronicity" and strength:
                importance = min(0.9, 0.5 + strength * 0.1)

            result = self._orchestrator.handle_store_memory(
                content=content,
                tags=commons_tags,
                importance=importance,
                summary=f"[{op_type}] {project_id}: {', '.join(tags[:5])}",
                skip_embedding=True,
            )
            new_memory_ids.append(result["memory_id"])
            processed += 1

        # Mark as processed
        signal_ids = [row["id"] for row in rows]
        placeholders = ",".join("?" * len(signal_ids))
        self._db.execute(
            f"UPDATE pending_signals SET processed = 1 WHERE id IN ({placeholders})",
            tuple(signal_ids),
        )
        self._db.connection.commit()

        # Batch embed all new memories
        if new_memory_ids:
            self._orchestrator._batch_embed_memories(new_memory_ids)

        return {
            "processed": processed,
            "memory_ids": new_memory_ids,
            "status": "ok",
        }

    def maybe_auto_process(self) -> dict[str, Any] | None:
        """Rate-limited auto-processing. Returns stats or None if skipped."""
        now = datetime.utcnow()
        if (
            self._last_process_time
            and (now - self._last_process_time).total_seconds() < 5.0
        ):
            return None
        self._last_process_time = now
        return self.process_pending()


def _build_commons_tags(
    project_id: str,
    op_type: str,
    tags: list[str],
    event_type: str | None = None,
) -> list[str]:
    """Build the dual tag set for a commons memory.

    Returns:
        - Project-namespaced tags: "projectname:tagname"
        - Shared tags: "tagname" (bridges across projects)
        - Project ID tag: "projectname"
        - Operation type tag: "store" / "retrieve" / "synchronicity"
        - Event sub-type tag if synchronicity
    """
    commons_tags = []

    # Project-namespaced tags
    for tag in tags:
        commons_tags.append(f"{project_id}:{tag}")

    # Shared (un-namespaced) tags
    commons_tags.extend(tags)

    # Meta tags
    commons_tags.append(project_id)
    commons_tags.append(op_type)

    if event_type:
        commons_tags.append(event_type.replace("_", "-"))

    return commons_tags
