import json
from abc import ABC, abstractmethod
from urllib import parse as urllib
from lib.common import rest_client
from lib.services.redis.base_client import BaseClient


class ParameterGroupClient(BaseClient):
    """Service client for ParameterGroup API"""

    def __init__(self, auth_provider, client, **kwargs):
        super().__init__(auth_provider=auth_provider, **kwargs)
        self.client = client

    def _parse_response(self, resp, body, schema):
        """Parse and validate response."""
        # Handle empty response bodies (e.g., validation endpoints)
        if not body or body.strip() == '':
            body_data = {}
        else:
            body_data = json.loads(body)

        self.validate_response(schema, resp, body_data)

        # Return format expected by tests: {'status': int, 'body': dict}
        return {
            'status': resp.status,
            'body': body_data
        }

    def list_parameter_groups(self, **params):
        """A list of parameter groups in the project."""
        url = self.client.get_parameter_groups_path(self.project_name)
        if params:
            url += f"?{urllib.urlencode(params)}"
        resp, body = self.get(url)
        return self._parse_response(
            resp, body, self.client.get_schema().list_parameter_groups
        )

    def create_parameter_group(self, **kwargs):
        """Create parameter group."""
        url = self.client.get_parameter_groups_path(self.project_name)
        post_body = json.dumps(kwargs)
        resp, body = self.post(url, post_body)
        return self._parse_response(
            resp, body, self.client.get_schema().create_parameter_group
        )

    def show_parameter_group(self, parameter_group_name):
        """Get parameter group."""
        url = self.client.get_parameter_group_path(self.project_name, parameter_group_name)
        resp, body = self.get(url)
        return self._parse_response(
            resp, body, self.client.get_schema().show_parameter_group
        )

    def update_parameter_group(self, parameter_group_name, **kwargs):
        """Update parameter group."""
        url = self.client.get_parameter_group_path(self.project_name, parameter_group_name)
        put_body = json.dumps(kwargs)
        resp, body = self.put(url, put_body)
        return self._parse_response(
            resp, body, self.client.get_schema().update_parameter_group
        )

    def delete_parameter_group(self, parameter_group_name):
        """Delete parameter group."""
        url = self.client.get_parameter_group_path(self.project_name, parameter_group_name)
        resp, body = self.delete(url)
        return self._parse_response(
            resp, body, self.client.get_schema().delete_parameter_group
        )

    def list_parameter_group_parameters(self, parameter_group_name, **params):
        """Get parameter group parameters."""
        url = self.client.get_parameter_group_parameters_path(self.project_name, parameter_group_name)
        if params:
            url += f"?{urllib.urlencode(params)}"
        resp, body = self.get(url)
        return self._parse_response(
            resp, body, self.client.get_schema().list_parameter_group_parameters
        )

    def validate_parameter_group_name(self, parameter_group_name):
        """Check the parameter group name is duplicated."""
        url = self.client.get_parameter_group_validate_path(self.project_name, parameter_group_name)
        resp, body = self.get(url)
        return self._parse_response(
            resp, body, self.client.get_schema().validate_parameter_group_name
        )


class ParameterGroupClientInterface(ABC):
    """Interface for cloud-specific implementations."""

    @abstractmethod
    def get_schema(self):
        """Return response schemas module."""
        pass

    @abstractmethod
    def get_parameter_groups_path(self, project_name):
        """Return API endpoint path for parameter groups."""
        pass

    @abstractmethod
    def get_parameter_group_path(self, project_name, parameter_group_name):
        """Return API endpoint path for a specific parameter group."""
        pass

    @abstractmethod
    def get_parameter_group_parameters_path(self, project_name, parameter_group_name):
        """Return API endpoint path for parameter group parameters."""
        pass

    @abstractmethod
    def get_parameter_group_validate_path(self, project_name, parameter_group_name):
        """Return API endpoint path for parameter group validation."""
        pass
