"""Feishu-owned helpers for its persisted multi-instance configuration."""

from __future__ import annotations

import re
from typing import Any, cast

from loguru import logger

from nanobot.channels.contracts import ChannelInstanceSpec, ChannelManagementSpec
from nanobot.channels.feishu.config import feishu_default_config
from nanobot.config.loader import merge_missing_defaults

DEFAULT_INSTANCE_ID = "default"
_INSTANCE_ID_RE = re.compile(r"^[A-Za-z0-9_-]+$")


def validate_instance_id(value: str) -> str:
    """Return a normalized instance id or raise ValueError."""
    instance_id = value.strip()
    if not instance_id or not _INSTANCE_ID_RE.fullmatch(instance_id):
        raise ValueError("instance id must match [A-Za-z0-9_-]+")
    return instance_id


def runtime_channel_name(base_name: str, instance_id: str) -> str:
    """Return the channel key used for routing messages at runtime."""
    return base_name if instance_id == DEFAULT_INSTANCE_ID else f"{base_name}.{instance_id}"


def managed_feishu_instance_specs(
    section: Any,
    *,
    enabled_only: bool = True,
) -> list[ChannelInstanceSpec]:
    return feishu_instance_specs(
        section,
        feishu_default_config(),
        enabled_only=enabled_only,
    )


def update_managed_feishu_instance(
    section: Any,
    values: dict[str, Any],
    *,
    instance_id: str = DEFAULT_INSTANCE_ID,
) -> dict[str, Any]:
    existing = cast(dict[str, Any], section) if isinstance(section, dict) else {}
    return upsert_feishu_instance(
        existing,
        feishu_default_config(),
        instance_id,
        values,
    )


def _base_feishu_instance_config(defaults: dict[str, Any]) -> dict[str, Any]:
    config = dict(defaults)
    config["instanceId"] = DEFAULT_INSTANCE_ID
    config["name"] = "nanobot"
    return config


def _normalize_feishu_instance(
    raw: dict[str, Any],
    defaults: dict[str, Any],
    *,
    inherited: dict[str, Any] | None = None,
    fallback_id: str = DEFAULT_INSTANCE_ID,
) -> dict[str, Any]:
    config = cast(dict[str, Any], merge_missing_defaults(inherited or {}, defaults))
    config = cast(dict[str, Any], merge_missing_defaults(raw, config))

    raw_id = raw.get("id") or raw.get("instanceId") or raw.get("instance_id") or fallback_id
    instance_id = validate_instance_id(str(raw_id))
    config["id"] = instance_id
    config["instanceId"] = instance_id
    config.setdefault("name", "nanobot" if instance_id == DEFAULT_INSTANCE_ID else f"nanobot {instance_id}")
    return config


def feishu_app_identity_key(app_id: Any, domain: Any = "feishu") -> str:
    """Return the stable identity shared by persisted and runtime instances."""
    app_id = str(app_id or "").strip()
    if not app_id:
        return ""
    normalized_domain = "lark" if str(domain or "feishu").strip().lower() == "lark" else "feishu"
    return f"{normalized_domain}:{app_id}"


def _feishu_instance_inputs(
    section: Any,
    defaults: dict[str, Any],
) -> tuple[list[Any], dict[str, Any] | None]:
    if hasattr(section, "model_dump"):
        section = section.model_dump(mode="json", by_alias=True)
    if not isinstance(section, dict):
        section = {}
    section_data = cast(dict[str, Any], section)

    instances = section_data.get("instances")
    if isinstance(instances, list):
        inherited = {key: value for key, value in section_data.items() if key != "instances"}
        return list(cast(list[Any], instances)), inherited
    return ([section_data] if section_data else [_base_feishu_instance_config(defaults)]), None


def feishu_instance_specs(
    section: Any,
    defaults: dict[str, Any],
    *,
    enabled_only: bool = False,
) -> list[ChannelInstanceSpec]:
    """Expand legacy or canonical Feishu config into runtime instance specs."""
    raw_specs, inherited = _feishu_instance_inputs(section, defaults)

    specs: list[ChannelInstanceSpec] = []
    instance_ids: set[str] = set()
    identity_owners: dict[str, str] = {}
    for index, raw in enumerate(raw_specs):
        if not isinstance(raw, dict):
            logger.warning("Skipping invalid Feishu instance at index {}: expected an object", index)
            continue
        fallback_id = DEFAULT_INSTANCE_ID if index == 0 else f"assistant-{index + 1}"
        try:
            config = _normalize_feishu_instance(
                cast(dict[str, Any], raw),
                defaults,
                inherited=inherited,
                fallback_id=fallback_id,
            )
        except ValueError as exc:
            logger.warning("Skipping invalid Feishu instance config: {}", exc)
            continue

        instance_id = str(config["instanceId"])
        if instance_id in instance_ids:
            logger.warning("Skipping duplicate Feishu instance id '{}'", instance_id)
            continue

        instance_ids.add(instance_id)
        enabled = bool(config.get("enabled", defaults.get("enabled", False)))
        if enabled_only and not enabled:
            continue

        identity = feishu_app_identity_key(
            config.get("appId") or config.get("app_id"),
            config.get("domain"),
        )
        if enabled_only and identity:
            if identity in identity_owners:
                logger.warning(
                    "Skipping Feishu instance '{}' because it uses the same app as instance '{}'",
                    instance_id,
                    identity_owners[identity],
                )
                continue
            identity_owners[identity] = instance_id

        specs.append(
            ChannelInstanceSpec(
                instance_id=instance_id,
                config=config,
            )
        )

    return specs


def canonical_feishu_section(section: Any, defaults: dict[str, Any]) -> dict[str, Any]:
    """Return a canonical section, rejecting input that cannot be preserved safely."""
    raw_specs, inherited = _feishu_instance_inputs(section, defaults)
    instances: list[dict[str, Any]] = []
    instance_ids: set[str] = set()

    for index, raw in enumerate(raw_specs):
        if not isinstance(raw, dict):
            raise ValueError(f"Feishu instance at index {index} must be an object")
        fallback_id = DEFAULT_INSTANCE_ID if index == 0 else f"assistant-{index + 1}"
        try:
            config = _normalize_feishu_instance(
                cast(dict[str, Any], raw),
                defaults,
                inherited=inherited,
                fallback_id=fallback_id,
            )
        except ValueError as exc:
            raise ValueError(f"Invalid Feishu instance at index {index}: {exc}") from exc

        instance_id = str(config["instanceId"])
        if instance_id in instance_ids:
            raise ValueError(f"duplicate Feishu instance id '{instance_id}'")
        instance_ids.add(instance_id)
        instances.append(config)

    return {"instances": instances}


def upsert_feishu_instance(
    section: Any,
    defaults: dict[str, Any],
    instance_id: str,
    values: dict[str, Any],
) -> dict[str, Any]:
    """Return canonical Feishu section with one instance created or updated."""
    instance_id = validate_instance_id(instance_id)
    canonical = canonical_feishu_section(section, defaults)
    instances = canonical.setdefault("instances", [])

    for instance in instances:
        if instance.get("id") == instance_id or instance.get("instanceId") == instance_id:
            instance.update(values)
            instance["id"] = instance_id
            instance["instanceId"] = instance_id
            instance.setdefault("name", "nanobot" if instance_id == DEFAULT_INSTANCE_ID else f"nanobot {instance_id}")
            return canonical

    config = _normalize_feishu_instance(
        {**values, "id": instance_id},
        defaults,
        fallback_id=instance_id,
    )
    instances.append(config)
    return canonical


def update_feishu_instance_preserving_shape(
    section: Any,
    defaults: dict[str, Any],
    instance_id: str,
    values: dict[str, Any],
) -> dict[str, Any]:
    """Update background metadata without migrating a legacy flat section."""
    instance_id = validate_instance_id(instance_id)
    if hasattr(section, "model_dump"):
        section = section.model_dump(mode="json", by_alias=True)

    if (
        instance_id == DEFAULT_INSTANCE_ID
        and isinstance(section, dict)
        and not isinstance(cast(dict[str, Any], section).get("instances"), list)
    ):
        return {**cast(dict[str, Any], section), **values}

    return upsert_feishu_instance(section, defaults, instance_id, values)


FEISHU_MANAGEMENT = ChannelManagementSpec(
    multi_instance=True,
    default_config=feishu_default_config,
    instance_specs=managed_feishu_instance_specs,
    update_instance_config=update_managed_feishu_instance,
    runtime_name=runtime_channel_name,
)


__all__ = [
    "DEFAULT_INSTANCE_ID",
    "FEISHU_MANAGEMENT",
    "canonical_feishu_section",
    "feishu_app_identity_key",
    "feishu_instance_specs",
    "runtime_channel_name",
    "update_feishu_instance_preserving_shape",
    "upsert_feishu_instance",
    "validate_instance_id",
]
