"""Validate dependencies."""
from __future__ import annotations

import pathlib
import re

import voluptuous as vol
from voluptuous.humanize import humanize_error

from homeassistant.const import CONF_SELECTOR
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv, selector
from homeassistant.util.yaml import load_yaml

from .model import Integration


def exists(value):
    """Check if value exists."""
    if value is None:
        raise vol.Invalid("Value cannot be None")
    return value


FIELD_SCHEMA = vol.Schema(
    {
        vol.Required("description"): str,
        vol.Optional("name"): str,
        vol.Optional("example"): exists,
        vol.Optional("default"): exists,
        vol.Optional("values"): exists,
        vol.Optional("required"): bool,
        vol.Optional("advanced"): bool,
        vol.Optional(CONF_SELECTOR): selector.validate_selector,
    }
)

SERVICE_SCHEMA = vol.Schema(
    {
        vol.Required("description"): str,
        vol.Optional("name"): str,
        vol.Optional("target"): vol.Any(
            selector.TargetSelector.CONFIG_SCHEMA, None  # pylint: disable=no-member
        ),
        vol.Optional("fields"): vol.Schema({str: FIELD_SCHEMA}),
    }
)

SERVICES_SCHEMA = vol.Schema({cv.slug: SERVICE_SCHEMA})


def grep_dir(path: pathlib.Path, glob_pattern: str, search_pattern: str) -> bool:
    """Recursively go through a dir and it's children and find the regex."""
    pattern = re.compile(search_pattern)

    for fil in path.glob(glob_pattern):
        if not fil.is_file():
            continue

        if pattern.search(fil.read_text()):
            return True

    return False


def validate_services(integration: Integration):
    """Validate services."""
    # Find if integration uses services
    has_services = grep_dir(
        integration.path,
        "**/*.py",
        r"(hass\.services\.(register|async_register))|async_register_entity_service|async_register_admin_service",
    )

    if not has_services:
        return

    try:
        data = load_yaml(str(integration.path / "services.yaml"))
    except FileNotFoundError:
        integration.add_error("services", "Registers services but has no services.yaml")
        return
    except HomeAssistantError:
        integration.add_error(
            "services", "Registers services but unable to load services.yaml"
        )
        return

    try:
        SERVICES_SCHEMA(data)
    except vol.Invalid as err:
        integration.add_error(
            "services", f"Invalid services.yaml: {humanize_error(data, err)}"
        )


def validate(integrations: dict[str, Integration], config):
    """Handle dependencies for integrations."""
    # check services.yaml is cool
    for integration in integrations.values():
        if not integration.manifest:
            continue

        validate_services(integration)

@@ -1772,24 +1772,133 @@
 ervices.%22%22%22%0A
+    try:%0A        data = load_yaml(str(integration.path / %22services.yaml%22))%0A    except FileNotFoundError:%0A    
     # Find i
@@ -1929,16 +1929,20 @@
 ces%0A    
+ 
+   
 has_serv
@@ -1958,32 +1958,36 @@
 ep_dir(%0A        
+    
 integration.path
@@ -1996,16 +1996,20 @@
         
+   
+ 
 %22**/*.py
@@ -2011,16 +2011,20 @@
 /*.py%22,%0A
+    
         
@@ -2130,16 +2130,20 @@
 rvice%22,%0A
+    
     )%0A%0A 
@@ -2145,22 +2145,22 @@
  )%0A%0A    
+  
+  
 if
- not
  has_ser
@@ -2178,125 +2178,8 @@
     
-return%0A%0A    try:%0A        data = load_yaml(str(integration.path / %22services.yaml%22))%0A    except FileNotFoundError:%0A    
     
@@ -2200,16 +2200,33 @@
 d_error(
+%0A                
 %22service
@@ -2274,16 +2274,29 @@
 es.yaml%22
+%0A            
 )%0A      
@@ -2369,58 +2369,22 @@
 ror(
-%0A            %22services%22, %22Registers services but u
+%22services%22, %22U
 nabl
@@ -2407,25 +2407,16 @@
 es.yaml%22
-%0A        
 )%0A      

Make hassfest service validation faster (#50003)