from .app_store_objects import *

from typing import Any, Callable
import json
from urllib import request


def _send_a_post(url: str, data: dict, headers: dict | None=None) -> str:
    a_request = request.Request(url, method="POST")
    a_request.add_header('Content-Type', 'application/json')
    if headers != None:
        for key, value in headers.items():
            a_request.add_header(key, value)
    data = json.dumps(data, indent=4)
    data = data.encode("utf-8", errors="ignore")
    r_ = request.urlopen(a_request, data=data)
    content = r_.read().decode("utf-8", errors="ignore")
    return content


class Client_app_store:
    def __init__(self, service_url: str, headers: dict[str, Any] | None = None, error_handle_function: Callable[[str], None] | None = None, special_error_key: str = "__yingshaoxo's_error__", interceptor_function: Callable[[dict], None] | None = None):
        if (service_url.endswith("/")):
            service_url = service_url[:-1]
        self._service_url = service_url 

        if headers == None:
            headers = {}
        self._header = headers

        def _default_error_handle_function(error_message: str):
            print(f"errors: {error_message}")
        if error_handle_function == None:
            error_handle_function = _default_error_handle_function
        self._error_handle_function = error_handle_function

        self._special_error_key = special_error_key

        def _default_interceptor_function(data: dict):
            pass
        if interceptor_function == None:
            interceptor_function = _default_interceptor_function
        self._interceptor_function = interceptor_function

    def _get_reponse_or_error_by_url_path_and_input(self, sub_url: str, input_dict: dict[str, Any]):
        the_url = f"{self._service_url}/app_store/{sub_url}/"
        try:
            response = _send_a_post(url=the_url, data=input_dict, headers=self._header)
            json_response = json.loads(response)
            self._interceptor_function(json_response)
            return json_response
        except Exception as e: 
            return {self._special_error_key: str(e)}

    def add_app(self, item: Add_App_Request, ignore_error: bool | None=None) -> Add_App_Response | None:
        result = self._get_reponse_or_error_by_url_path_and_input("add_app", item.to_dict())
        if self._special_error_key in result.keys():
            if ((ignore_error == None) or ((ignore_error != None) and (not ignore_error))):
                self._error_handle_function(result[self._special_error_key])
            return None
        else:
            return Add_App_Response().from_dict(result)

    def search_app(self, item: Search_App_Request, ignore_error: bool | None=None) -> Search_App_Response | None:
        result = self._get_reponse_or_error_by_url_path_and_input("search_app", item.to_dict())
        if self._special_error_key in result.keys():
            if ((ignore_error == None) or ((ignore_error != None) and (not ignore_error))):
                self._error_handle_function(result[self._special_error_key])
            return None
        else:
            return Search_App_Response().from_dict(result)

    def get_app_detail(self, item: Get_App_Detail_Request, ignore_error: bool | None=None) -> Get_App_Detail_Response | None:
        result = self._get_reponse_or_error_by_url_path_and_input("get_app_detail", item.to_dict())
        if self._special_error_key in result.keys():
            if ((ignore_error == None) or ((ignore_error != None) and (not ignore_error))):
                self._error_handle_function(result[self._special_error_key])
            return None
        else:
            return Get_App_Detail_Response().from_dict(result)

    def export_data(self, item: Export_Data_Request, ignore_error: bool | None=None) -> Export_Data_Response | None:
        result = self._get_reponse_or_error_by_url_path_and_input("export_data", item.to_dict())
        if self._special_error_key in result.keys():
            if ((ignore_error == None) or ((ignore_error != None) and (not ignore_error))):
                self._error_handle_function(result[self._special_error_key])
            return None
        else:
            return Export_Data_Response().from_dict(result)