import enum
from datetime import datetime
from typing import List

import requests
from django.conf import settings as s

# Once stable these will be exposed by enviPy-plugins lib
from envipy_additional_information import EnviPyModel, UIConfig, WidgetType  # noqa: I001
from envipy_additional_information import register  # noqa: I001

from bridge.contracts import Classifier  # noqa: I001
from bridge.dto import (
    BuildResult,
    EnviPyDTO,
    EvaluationResult,
    RunResult,
    TransformationProductPrediction,
)  # noqa: I001


class BiotransformerEnvType(enum.Enum):
    CYP450 = "CYP450"
    ALLHUMAN = "ALLHUMAN"
    ECBASED = "ECBASED"
    HGUT = "HGUT"
    PHASEII = "PHASEII"
    ENV = "ENV"


@register("biotransformerconfig")
class BiotransformerConfig(EnviPyModel):
    env_type: BiotransformerEnvType

    class UI:
        title = "Biotransformer Type"
        env_type = UIConfig(widget=WidgetType.SELECT, label="Biotransformer Type", order=1)


class Biotransformer(Classifier):
    Config = BiotransformerConfig

    def __init__(self, config: BiotransformerConfig | None = None):
        super().__init__(config)
        self.url = f"{s.BIOTRANSFORMER_URL}/biotransformer"

    @classmethod
    def requires_rule_packages(cls) -> bool:
        return False

    @classmethod
    def requires_data_packages(cls) -> bool:
        return False

    @classmethod
    def identifier(cls) -> str:
        return "biotransformer3"

    @classmethod
    def name(cls) -> str:
        return "Biotransformer 3.0"

    @classmethod
    def display(cls) -> str:
        return "Biotransformer 3.0"

    def build(self, eP: EnviPyDTO, *args, **kwargs) -> BuildResult | None:
        return

    def run(self, eP: EnviPyDTO, *args, **kwargs) -> RunResult:
        smiles = [c.smiles for c in eP.get_compounds()]
        preds = self._post(smiles)

        results = []

        for substrate in preds.keys():
            results.append(
                TransformationProductPrediction(
                    substrate=substrate,
                    products=preds[substrate],
                )
            )

        return RunResult(
            producer=eP.get_context().url,
            description=f"Generated at {datetime.now()}",
            result=results,
        )

    def evaluate(self, eP: EnviPyDTO, *args, **kwargs) -> EvaluationResult:
        pass

    def build_and_evaluate(self, eP: EnviPyDTO, *args, **kwargs) -> EvaluationResult:
        pass

    def _post(self, smiles: List[str]) -> dict[str, dict[str, float]]:
        data = {"substrates": smiles, "mode": self.config.env_type.value}
        res = requests.post(self.url, json=data)

        res.raise_for_status()

        # Example Response JSON:
        # {
        #     'products': {
        #         'CN1C=NC2=C1C(=O)N(C(=O)N2C)C': {
        #             'CN1C2=C(C(=O)N(C)C1=O)NC=N2': 0.5,
        #             'CN1C=NC2=C1C(=O)N(C)C(=O)N2.CN1C=NC2=C1C(=O)NC(=O)N2C.CO': 0.5
        #         }
        #     }
        # }

        return res.json()["products"]
