from dataclasses import dataclass
from typing import Optional

from johnsnowlabs import settings
from johnsnowlabs.abstract_base.base_enum import BaseEnum
from johnsnowlabs.py_models.lib_version import LibVersion
from johnsnowlabs.py_models.primitive import LibVersionIdentifier


class DatabricksClusterStates(BaseEnum):
    # https://docs.databricks.com/dev-tools/api/latest/clusters.html#clusterclusterstate
    PENDING = "PENDING"
    RUNNING = "RUNNING"
    RESTARTING = "RESTARTING"
    RESIZING = "RESIZING"
    TERMINATING = "TERMINATING"
    TERMINATED = "TERMINATED"
    ERROR = "ERROR"
    UNKNOWN = "UNKNOWN"


class JvmHardwareTarget(BaseEnum):
    gpu = "gpu"
    cpu = "cpu"
    m1 = "apple_silicon"
    aarch = "aarch"

    @classmethod
    def bool_choice_to_hardware(
        cls, gpu: bool = False, cpu: bool = False, m1: bool = False
    ) -> "JvmHardwareTarget":
        if gpu:
            return cls.gpu
        elif cpu:
            return cls.cpu
        elif m1:
            return cls.m1
        else:
            return cls.cpu

    @staticmethod
    def from_str(s):
        if s not in JvmHardwareTarget:
            bck = "\n"
            raise Exception(
                f"Invalid value for jvm_install_type: {s}"
                f" please specify on of:\n{bck.join([n.value for n in JvmHardwareTarget])}"
            )
        else:
            return JvmHardwareTarget(s)


class PyInstallTypes(BaseEnum):
    tar = "tar.gz"
    wheel = "whl"

    @staticmethod
    def from_str(s):
        bck = "\n"
        if s not in PyInstallTypes:
            raise Exception(
                f"Invalid value for py_install_type: {s}"
                f" please specify on of:\n{bck.join([n.value for n in PyInstallTypes])}"
            )
        else:
            return PyInstallTypes(s)


class SparkVersion(BaseEnum):
    # Broad versions
    spark3xx = LibVersion("3.x.x")
    spark31x = LibVersion("3.1.x")
    spark32x = LibVersion("3.2.x")
    spark33x = LibVersion("3.3.x")
    spark330 = LibVersion("3.3.0")
    spark322 = LibVersion("3.2.2")
    spark321 = LibVersion("3.2.1")
    spark320 = LibVersion("3.2.0")
    spark313 = LibVersion("3.1.3")
    spark312 = LibVersion("3.1.2")
    spark311 = LibVersion("3.1.1")
    spark303 = LibVersion("3.0.3")
    spark302 = LibVersion("3.0.2")
    spark301 = LibVersion("3.0.1")
    spark300 = LibVersion("3.0.0")


class LicenseType(BaseEnum):
    trial = "Trial"
    research = "Research"


class LicensePlattform(BaseEnum):
    none = None
    databricks = "Databricks"
    floating = "Floating"


class ProductName(BaseEnum):
    hc = "Spark-Healthcare"
    nlp = "Spark-NLP"
    ocr = "Spark-OCR"
    finance = "Spark-Finance"
    nlp_display = "NLP-Display"
    nlu = "nlu"
    jsl_full = "full"
    pyspark = "PySpark"
    spark = "spark"
    java = "java"
    python = "python"
    jsl_lib = "John Snow Labs Python Library"

    @staticmethod
    def from_str(s):
        bck = "\n"
        if s not in ProductName:
            raise Exception(
                f"Invalid Product to install: {s}"
                f" please specify on of:\n{bck.join([n.value for n in ProductName])}"
            )
        else:
            return ProductName(s)

    @staticmethod
    def from_jsl_api(s: str):
        if s == "Visual NLP":
            return ProductName.ocr
        if s == "Healthcare NLP":
            return ProductName.hc
        if s == "Spark NLP":
            return ProductName.hc
        if s == "Finance NLP":
            return ProductName.hc
        if s == "Legal NLP":
            return ProductName.hc

        raise ValueError(f"Unknown product name from jsl-api {s}")


class ProductLogo(BaseEnum):
    hc = "💊"  # 🏥 🩺 💊 ❤️ ‍🩹 ‍⚕️💉 🥼 🚑 🔬 🫀 🩻 🧪
    nlp = "🚀"
    ocr = "🕶"  # 👁️  🤖 🦾🦿 🥽 👀 🕶 🥽 ⚕
    finance = "🤑"  # 🤑🏦💲💳💰💸💵💴💶💷
    nlp_display = "🎨"
    nlu = "🤖"
    jsl_full = "💯🕴"  # 🕴
    java = "🫘"  # 🫘 # ☕ ♨ 🥃 🥃 🧋🍹♨️🥤🫖
    python = "🐍"  # 🐉
    pyspark = "🐍+⚡"
    spark = "⚡ "
    databricks = "🧱"
    jsl_lib = "🧪"


class ProductSlogan(BaseEnum):
    healthcare = "Heal the planet with NLP!"
    spark_nlp = "State of the art NLP at scale"
    ocr = "Empower your NLP with a set of eyes"
    pyspark = "The big data Engine"
    nlu = "1 line of code to conquer nlp!"
    jsl_full = "The entire John Snow Labs arsenal!"
    finance = "NLP for the Finance Industry"
    nlp_display = "Visualize and Explain NLP!"
    jsl_lib = "Easy access to all of John Snow Labs Enterprise Software!"
    spark = "⚡"
    java = "☕"
    python = "🐍"


@dataclass
class InstalledProductInfo:
    """Representation of a JSL product install. Version is None if not installed"""

    product: ProductName
    version: Optional[LibVersionIdentifier] = None


@dataclass
class JslSuiteStatus:
    """Representation and install status of all JSL products and its dependencies.
    Version attribute of InstalledProductInfo is None for uninstalled products
    """

    spark_nlp_info: Optional[InstalledProductInfo] = None
    spark_hc_info: Optional[InstalledProductInfo] = None
    spark_ocr_info: Optional[InstalledProductInfo] = None
    nlu_info: Optional[InstalledProductInfo] = None
    sparknlp_display_info: Optional[InstalledProductInfo] = None
    pyspark_info: Optional[InstalledProductInfo] = None


class LatestCompatibleProductVersion(BaseEnum):
    jsl_lib = LibVersion(settings.raw_version_jsl_lib)
    healthcare = LibVersion(settings.raw_version_medical)
    spark_nlp = LibVersion(settings.raw_version_nlp)
    ocr = LibVersion(settings.raw_version_ocr)
    nlu = LibVersion(settings.raw_version_nlu)
    nlp_display = LibVersion(settings.raw_version_nlp_display)
    pyspark = LibVersion(settings.raw_version_pyspark)
    finance = LibVersion("finance")
    spark = LibVersion(settings.raw_version_pyspark)
    java = LibVersion("java")
    python = LibVersion("python")

    @staticmethod
    def from_settings(p: ProductName):
        if p == ProductName.hc:
            return settings.raw_version_medical
        if p == ProductName.ocr:
            return settings.raw_version_ocr
        if p == ProductName.nlp:
            return settings.raw_version_nlp

    @staticmethod
    def sct_from_settings(p: ProductName):
        if p == ProductName.hc:
            return settings.raw_version_secret_medical
        if p == ProductName.ocr:
            return settings.raw_version_secret_ocr
        if p == ProductName.nlp:
            return settings.raw_version_nlp
