"""Generate zeroconf file."""

from __future__ import annotations

from collections import defaultdict

from homeassistant.loader import (
    async_process_zeroconf_match_dict,
    homekit_always_discover,
)

from .model import Config, Integration
from .serializer import format_python_namespace


def generate_and_validate(integrations: dict[str, Integration]) -> str:
    """Validate and generate zeroconf data."""
    service_type_dict = defaultdict(list)
    homekit_dict: dict[str, dict[str, str]] = {}

    for domain in sorted(integrations):
        integration = integrations[domain]
        service_types = integration.manifest.get("zeroconf", [])
        homekit = integration.manifest.get("homekit", {})
        homekit_models = homekit.get("models", [])

        if not (service_types or homekit_models):
            continue

        for entry in service_types:
            data = {"domain": domain}
            if isinstance(entry, dict):
                typ = entry["type"]
                data.update(async_process_zeroconf_match_dict(entry))
            else:
                typ = entry

            service_type_dict[typ].append(data)

        for model in homekit_models:
            if model in homekit_dict:
                integration.add_error(
                    "zeroconf",
                    f"Integrations {domain} and {homekit_dict[model]} "
                    "have overlapping HomeKit models",
                )
                break

            homekit_dict[model] = {
                "domain": domain,
                "always_discover": homekit_always_discover(
                    integration.manifest["iot_class"]
                ),
            }

    # HomeKit models are matched on starting string, make sure none overlap.
    warned = set()
    for key, value in homekit_dict.items():
        if key in warned:
            continue

        # n^2 yoooo
        for key_2, value_2 in homekit_dict.items():
            if key == key_2 or key_2 in warned:
                continue

            if key.startswith(key_2) or key_2.startswith(key):
                integration.add_error(
                    "zeroconf",
                    f"Integrations {value} and {value_2} "
                    "have overlapping HomeKit models",
                )
                warned.add(key)
                warned.add(key_2)
                break

    return format_python_namespace(
        {
            "HOMEKIT": {key: homekit_dict[key] for key in homekit_dict},
            "ZEROCONF": {key: service_type_dict[key] for key in service_type_dict},
        }
    )


def validate(integrations: dict[str, Integration], config: Config) -> None:
    """Validate zeroconf file."""
    zeroconf_path = config.root / "homeassistant/generated/zeroconf.py"
    config.cache["zeroconf"] = content = generate_and_validate(integrations)

    if config.specific_integrations:
        return

    if zeroconf_path.read_text() != content:
        config.add_error(
            "zeroconf",
            "File zeroconf.py is not up to date. Run python3 -m script.hassfest",
            fixable=True,
        )


def generate(integrations: dict[str, Integration], config: Config) -> None:
    """Generate zeroconf file."""
    zeroconf_path = config.root / "homeassistant/generated/zeroconf.py"
    zeroconf_path.write_text(f"{config.cache['zeroconf']}")
