# SPDX-License-Identifier: AGPL-3.0-only
# Copyright (c) 2026 sol pbc

"""Entity seeding functions.

This module handles seeding entities from structured imports:
- seed_entities: Match or create entities and add optional observations
"""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from solstone.think.journal_io import LockTimeout

if TYPE_CHECKING:
    from solstone.think.entities.core import EntityDict

logger = logging.getLogger(__name__)


def seed_entities(
    facet: str,
    day: str,
    entities: list[dict],
) -> list[EntityDict]:
    """Seed entities from structured imports.

    Each dict should have: name (required), type (default "Person"),
    email (optional), context (optional), observations (optional list of strings).

    Matches by email first, then name. Creates new entities for non-matches.
    If observations are provided, adds them via add_observation() with dedup.

    Args:
        facet: Facet name for entity context
        day: Day string YYYYMMDD for activity tracking
        entities: List of entity dicts to seed

    Returns:
        List of resolved/created entity dicts
    """
    from solstone.think.entities.core import entity_slug
    from solstone.think.entities.journal import (
        create_journal_entity,
        load_all_journal_entities,
        load_journal_entity,
        save_journal_entity,
    )
    from solstone.think.entities.matching import (
        EntityResolutionOutcome,
        ResolutionOrigin,
        ResolutionScope,
        find_entity_by_email,
        record_entity_resolution,
    )
    from solstone.think.entities.observations import add_observation, load_observations

    # Load all journal entities for matching
    all_entities = load_all_journal_entities()
    entity_list = list(all_entities.values())

    resolved: list[EntityDict] = []
    facet_ensured = False
    ambiguous = 0
    scope = ResolutionScope.journal()

    for ent in entities:
        name = ent.get("name", "").strip()
        if not name:
            continue

        entity_type = ent.get("type", "Person")
        email = ent.get("email", "")

        matched = None

        # Try email match first
        if email:
            matched = find_entity_by_email(email, entity_list)

        # Fall back to name match
        if not matched:
            resolution = record_entity_resolution(
                name,
                entity_list,
                scope=scope,
                origin=ResolutionOrigin(
                    lane="think.entities.seed_entities",
                    facet=facet,
                    day=day,
                    field="name",
                ),
            )
            if resolution.outcome == EntityResolutionOutcome.AMBIGUOUS:
                ambiguous += 1
                continue
            if (
                resolution.outcome == EntityResolutionOutcome.RESOLVED
                and resolution.entity
            ):
                matched = resolution.entity

        if matched:
            # Merge email into existing entity if new
            if email:
                existing_emails = set(e.lower() for e in matched.get("emails", []))
                if email.lower() not in existing_emails:
                    matched["emails"] = sorted(existing_emails | {email.lower()})
                    save_journal_entity(matched)
            resolved.append(matched)
            resolved_name = matched.get("name", name)
        else:
            # Create new entity
            eid = entity_slug(name)
            emails = [email.lower()] if email else None
            new_entity = load_journal_entity(eid) or create_journal_entity(
                entity_id=eid,
                name=name,
                entity_type=entity_type,
                emails=emails,
            )
            entity_list.append(new_entity)  # Add to list for future matches
            resolved.append(new_entity)
            resolved_name = new_entity.get("name", name)

        # Add observations if provided, with dedup
        observations = ent.get("observations", [])
        if observations:
            existing_obs = load_observations(facet, resolved_name)
            existing_contents = {o["content"] for o in existing_obs}
            for obs_content in observations:
                if obs_content not in existing_contents:
                    if not facet_ensured:
                        from solstone.think.facets import ensure_facet

                        ensure_facet(facet)
                        facet_ensured = True
                    try:
                        add_observation(
                            facet, resolved_name, obs_content, source_day=day
                        )
                    except LockTimeout:
                        logger.warning(
                            "observations busy for %s; skipping remaining",
                            resolved_name,
                        )
                        break
                    existing_contents.add(obs_content)

    if ambiguous:
        logger.warning("seed_entities: skipped %d ambiguous entities", ambiguous)

    return resolved
