import json
import base64
import requests
import ddgs
import typing

from .validator import barcode_validator
from .exception import bad_request_exception
from .exception import autoadder_exception
from .gemini_search import gemini_search

class autoadder:
    def __init__(self, apikey: str, engine: str) -> None:
        self.__apikey = apikey
        self.__engine = engine
        self.__gemini = gemini_search(apikey)

    def __ddg(self) -> ddgs.DDGS:
        return ddgs.DDGS()

    def __search(self, phrase: str) -> str:
        for count in self.__ddg().text(phrase, max_results = 1):
            return count["title"]
        
        return phrase

    def __search_images(self, phrase: str) -> typing.Iterable[str]:
        for count in self.__ddg().images(phrase, max_results = 10):
            yield count["image"]

        yield phrase

    def __check_barcode(self, barcode: str) -> None:
        if barcode_validator(barcode).invalid:
            raise bad_request_exception("Invalid barcode")

    def __image_request(self, source: str) -> [str, str]:
        request = requests.get(source, timeout = 3)

        if not request.ok or not "Content-Type" in request.headers:
            raise bad_request_exception("Can nor fetch image")

        image = request.content
        encoded = base64.b64encode(image)
        extension = request.headers["Content-Type"]

        return encoded, extension

    def __try_images(self, images: list) -> [str, str]:
        for count in images:
            try:
                return self.__image_request(count)
            except:
                continue

    def __gemini_find(self, barcode: str) -> dict:
        result = self.__gemini.search(barcode)
        
        title = result["title"]
        description = result["description"]
        author = result["author"]

        images_url = self.__search_images(barcode)
        image, image_type = self.__try_images(images_url)

        splited = title.split(" ")

        if len(splited) > 3:
            title = " ".join(splited[0:3])

        return {
            "title": title,
            "description": description,
            "author": author,
            "barcode": barcode,
            "image": image,
            "image_type": image_type,
            "from": "gemini"
        }

    def __duck_duck_find(self, barcode: str) -> dict:
        self.__check_barcode(barcode)

        title = self.__search(barcode)
        description = title
        author = "Somebody"
        image = ""
        image_type = ""
        images_url = self.__search_images(barcode)
        image, image_type = self.__try_images(images_url)

        splited = title.split(" ")

        if len(splited) > 3:
            title = " ".join(splited[0:3])

        return {
            "title": title,
            "description": description,
            "author": author,
            "barcode": barcode,
            "image": image,
            "image_type": image_type,
            "from": "duckduckgo"
        }

    def find(self, barcode: str) -> dict:
        try:
            return self.__gemini_find(barcode)
        except Exception as error:
            duck_duck_go = self.__duck_duck_find(barcode)
            duck_duck_go["cause"] = str(error)

            return duck_duck_go