"""
service.py

LeafDoctor AI - Business Service Layer
"""

from __future__ import annotations

import shutil
import uuid
from datetime import datetime
from pathlib import Path

from sqlalchemy import func, text
from sqlalchemy.orm import Session

from config import settings
from gemini import GeminiClient, DiagnosisResult
from models import (
    DiagnosisHistory,
    ProtectionLabel,
    TreatmentMapping,
)


class DiagnosisService:

    def __init__(self, db: Session):
        self.db = db
        self.gemini = GeminiClient.instance()

    # --------------------------------------------------
    # Image
    # --------------------------------------------------

    def _generate_filename(self, extension: str) -> str:
        timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
        random_id = uuid.uuid4().hex[:8]
        return f"{timestamp}_{random_id}{extension}"

    def save_image(self, image_path: str | Path) -> Path:
        image_path = Path(image_path)
        if not image_path.exists():
            raise FileNotFoundError(image_path)

        extension = image_path.suffix.lower()
        filename = self._generate_filename(extension)
        destination = settings.upload_path / filename

        destination.parent.mkdir(parents=True, exist_ok=True)
        shutil.copy2(image_path, destination)
        return destination

    # --------------------------------------------------
    # Protection Label
    # --------------------------------------------------

    def get_label(self, label: str) -> ProtectionLabel:
        cleaned_label = label.strip().lower()
        obj = (
            self.db.query(ProtectionLabel)
            .filter(
                func.lower(func.trim(ProtectionLabel.label_name_en)) == cleaned_label
            )
            .first()
        )

        if obj is None:
            raise ValueError(f"Unknown label '{label}'")

        return obj

    # --------------------------------------------------
    # Treatment
    # --------------------------------------------------

    def get_treatments(self, class_id: int, crop: str) -> list[TreatmentMapping]:
        return (
            self.db.query(TreatmentMapping)
            .filter(
                TreatmentMapping.class_id == class_id,
                func.lower(TreatmentMapping.crop_en) == crop.lower(),
            )
            .all()
        )

    # --------------------------------------------------
    # History
    # --------------------------------------------------

    def save_history(
        self,
        image_path: str,
        diagnosis: DiagnosisResult,
        treatment: TreatmentMapping | None,
        class_id: int,
        user_id: str | None = None,
        user_ph: str | None = None,
    ) -> DiagnosisHistory:

        history = DiagnosisHistory(
            user_id=user_id,
            user_ph=user_ph,
            image_path=image_path,
            crop_detected=diagnosis.crop,
            predicted_label=diagnosis.label,
            class_id=class_id,
            confidence=diagnosis.confidence,
            treatment_id=(treatment.id if treatment else None),
            gemini_model=diagnosis.model,
            raw_response=diagnosis.raw_response,
        )

        try:
            self.db.add(history)
            self.db.commit()
            self.db.refresh(history)
            return history
        except Exception:
            self.db.rollback()
            raise

    # --------------------------------------------------
    # Helpers
    # --------------------------------------------------

    @staticmethod
    def best_treatment(treatments: list[TreatmentMapping]) -> TreatmentMapping | None:
        if not treatments:
            return None

        return sorted(
            treatments,
            key=lambda x: (
                x.chemical is None,
                x.dosage is None,
                x.sms_en is None,
            ),
        )[0]

    # --------------------------------------------------
    # Diagnosis Pipeline
    # --------------------------------------------------

    def diagnose(
        self,
        image_path: str | Path,
        user_id: str | None = None,
        user_ph: str | None = None,
    ) -> dict:

        stored_image = self.save_image(image_path)
        diagnosis = self.gemini.diagnose(stored_image)
        label = self.get_label(diagnosis.label)
        treatments = self.get_treatments(
            class_id=label.class_id,
            crop=diagnosis.crop,
        )
        treatment = self.best_treatment(treatments)

        history = self.save_history(
            image_path=str(stored_image),
            diagnosis=diagnosis,
            treatment=treatment,
            class_id=label.class_id,
            user_id=user_id,
            user_ph=user_ph,
        )

        return self._build_response(
            history=history,
            diagnosis=diagnosis,
            label=label,
            treatments=treatments,
            stored_image=stored_image,
        )

    # --------------------------------------------------
    # Response Builder
    # --------------------------------------------------

    # def _build_response(
    #     self,
    #     history: DiagnosisHistory,
    #     diagnosis: DiagnosisResult,
    #     label: ProtectionLabel,
    #     treatments: list[TreatmentMapping],
    #     stored_image: Path,
    # ) -> dict:

    #     recommendations = []
    #     for item in treatments:
    #         recommendations.append(
    #             {
    #                 "id": item.id,
    #                 "crop": {
    #                     "en": item.crop_en,
    #                     "bn": item.crop_bn,
    #                 },
    #                 "problem_type": {
    #                     "en": item.problem_type_en,
    #                     "bn": item.problem_type_bn,
    #                 },
    #                 "chemical": item.chemical,
    #                 "chemical_type": item.chemical_type,
    #                 "dosage": item.dosage,
    #                 "sms": {
    #                     "en": item.sms_en,
    #                     "bn": item.sms_bn,
    #                 },
    #             }
    #         )

    #     return {
    #         "success": True,
    #         "history_id": history.id,
    #         "user_id": history.user_id,
    #         "user_ph": history.user_ph,
    #         "image": str(stored_image),
    #         "diagnosis": {
    #             "class_id": label.class_id,
    #             "confidence": diagnosis.confidence,
    #             "crop": {
    #                 "en": diagnosis.crop,
    #                 "bn": (treatments[0].crop_bn if treatments else None),
    #             },
    #             "problem": {
    #                 "en": label.label_name_en,
    #                 "bn": label.label_name_bn,
    #             },
    #             "category": {
    #                 "en": label.primary_category_en,
    #                 "bn": label.primary_category_bn,
    #             },
    #             "gemini_model": diagnosis.model,
    #         },
    #         "recommendations": recommendations,
    #     }


    def _build_response(
        self,
        history: DiagnosisHistory,
        diagnosis: DiagnosisResult,
        label: ProtectionLabel,
        treatments: list[TreatmentMapping],
        stored_image: Path,
    ) -> dict:

        recommendations = []

        for item in treatments:
            recommendations.append(
                {
                    "id": item.id,
                    "crop": {
                        "en": item.crop_en,
                        "bn": item.crop_bn,
                    },
                    "problem_type": {
                        "en": item.problem_type_en,
                        "bn": item.problem_type_bn,
                    },
                    "chemical": item.chemical,
                    "chemical_type": item.chemical_type,
                    "dosage": item.dosage,
                    "sms": {
                        "en": item.sms_en,
                        "bn": item.sms_bn,
                    },
                }
            )

        return {
            "success": True,
            "history_id": history.id,
            "user_id": history.user_id,
            "user_ph": history.user_ph,
            "image": f"/uploads/{stored_image.name}",  # <--- Clean URL path
            "diagnosis": {
                "class_id": label.class_id,
                "confidence": diagnosis.confidence,
                "crop": {
                    "en": diagnosis.crop,
                    "bn": (
                        treatments[0].crop_bn
                        if treatments
                        else None
                    ),
                },
                "problem": {
                    "en": label.label_name_en,
                    "bn": label.label_name_bn,
                },
                "category": {
                    "en": label.primary_category_en,
                    "bn": label.primary_category_bn,
                },
                "gemini_model": diagnosis.model,
            },
            "recommendations": recommendations,
        }

    # --------------------------------------------------
    # Utility Methods
    # --------------------------------------------------

    def get_history(self, history_id: int) -> DiagnosisHistory | None:
        return (
            self.db.query(DiagnosisHistory)
            .filter(DiagnosisHistory.id == history_id)
            .first()
        )

    def get_histories(self, limit: int = 50) -> list[DiagnosisHistory]:
        return (
            self.db.query(DiagnosisHistory)
            .order_by(DiagnosisHistory.created_at.desc())
            .limit(limit)
            .all()
        )

    def get_user_histories(
        self,
        user_id: str | None = None,
        user_ph: str | None = None,
        limit: int = 50,
    ) -> list[dict]:
        if not user_id and not user_ph:
            return []

        query = self.db.query(DiagnosisHistory)

        if user_id and user_ph:
            query = query.filter(
                (DiagnosisHistory.user_id == user_id) | 
                (DiagnosisHistory.user_ph == user_ph)
            )
        elif user_id:
            query = query.filter(DiagnosisHistory.user_id == user_id)
        elif user_ph:
            query = query.filter(DiagnosisHistory.user_ph == user_ph)

        histories = (
            query.order_by(DiagnosisHistory.created_at.desc())
            .limit(limit)
            .all()
        )

        result = []
        for item in histories:
            # Look up treatment directly by class_id and crop
            treatments = self.get_treatments(
                class_id=item.class_id,
                crop=item.crop_detected,
            )
            treatment = self.best_treatment(treatments)

            result.append(
                {
                    "id": item.id,
                    "user_id": item.user_id,
                    "user_ph": item.user_ph,
                    "image": f"/uploads/{Path(item.image_path).name}",
                    "crop": item.crop_detected,
                    "label": item.predicted_label,
                    "class_id": item.class_id,
                    "confidence": item.confidence,
                    "sms_en": treatment.sms_en if treatment else None,
                    "created_at": item.created_at,
                }
            )

        return result

    def delete_history(self, history_id: int) -> bool:
        history = self.get_history(history_id)
        if history is None:
            return False

        try:
            image_path = Path(history.image_path)
            if image_path.exists():
                image_path.unlink()
        except Exception:
            pass

        self.db.delete(history)
        self.db.commit()
        return True

    # --------------------------------------------------
    # Health Check
    # --------------------------------------------------

    def health(self):
        database = "connected"
        gemini = "connected"

        try:
            self.db.execute(text("SELECT 1"))
        except Exception:
            database = "disconnected"

        try:
            self.gemini.test_connection()
        except Exception:
            gemini = "disconnected"

        return {
            "success": database == "connected" and gemini == "connected",
            "database": database,
            "gemini": gemini,
            "model": self.gemini.model,
        }

    # --------------------------------------------------
    # Statistics
    # --------------------------------------------------

    def statistics(self) -> dict:
        total_labels = self.db.query(ProtectionLabel).count()
        total_treatments = self.db.query(TreatmentMapping).count()
        total_diagnosis = self.db.query(DiagnosisHistory).count()

        return {
            "labels": total_labels,
            "treatments": total_treatments,
            "diagnosis_history": total_diagnosis,
        }


































    # """
# service.py

# LeafDoctor AI

# Business Service Layer

# Part 1
# """

# from __future__ import annotations

# import shutil
# import uuid
# from datetime import datetime
# from pathlib import Path

# from sqlalchemy import func
# from sqlalchemy.orm import Session

# from config import settings
# from gemini import GeminiClient, DiagnosisResult
# from models import (
#     DiagnosisHistory,
#     ProtectionLabel,
#     TreatmentMapping,
# )


# class DiagnosisService:

#     def __init__(self, db: Session):

#         self.db = db

#         self.gemini = GeminiClient.instance()

#     # --------------------------------------------------
#     # Image
#     # --------------------------------------------------

#     def _generate_filename(
#         self,
#         extension: str,
#     ) -> str:

#         timestamp = datetime.now().strftime(
#             "%Y%m%d%H%M%S"
#         )

#         random_id = uuid.uuid4().hex[:8]

#         return (
#             f"{timestamp}_"
#             f"{random_id}"
#             f"{extension}"
#         )

#     def save_image(
#         self,
#         image_path: str | Path,
#     ) -> Path:

#         image_path = Path(image_path)

#         if not image_path.exists():

#             raise FileNotFoundError(
#                 image_path
#             )

#         extension = image_path.suffix.lower()

#         filename = self._generate_filename(
#             extension
#         )

#         destination = (
#             settings.upload_path /
#             filename
#         )

#         destination.parent.mkdir(
#             parents=True,
#             exist_ok=True,
#         )

#         shutil.copy2(
#             image_path,
#             destination,
#         )

#         return destination

#     # --------------------------------------------------
#     # Protection Label
#     # --------------------------------------------------

#     def get_label(
#         self,
#         label: str,
#     ) -> ProtectionLabel:

#         obj = (
#             self.db.query(
#                 ProtectionLabel
#             )
#             .filter(
#                 func.lower(
#                     ProtectionLabel.label_name_en
#                 ) == label.lower()
#             )
#             .first()
#         )

#         if obj is None:
#             raise ValueError(
#                 f"Unknown label '{label}'"
#             )

#         return obj

#     # --------------------------------------------------
#     # Treatment
#     # --------------------------------------------------

#     def get_treatments(
#         self,
#         class_id: int,
#         crop: str,
#     ) -> list[TreatmentMapping]:

#         return (
#             self.db.query(
#                 TreatmentMapping
#             )
#             .filter(
#                 TreatmentMapping.class_id == class_id,
#                 func.lower(
#                     TreatmentMapping.crop_en
#                 ) == crop.lower(),
#             )
#         )

#     # --------------------------------------------------
#     # History
#     # --------------------------------------------------

#     def save_history(
#         self,
#         image_path: str,
#         diagnosis: DiagnosisResult,
#         treatment: TreatmentMapping | None,
#         class_id: int,
#     ) -> DiagnosisHistory:

#         history = DiagnosisHistory(

#             image_path=image_path,

#             crop_detected=diagnosis.crop,

#             predicted_label=diagnosis.label,

#             class_id=class_id,

#             confidence=diagnosis.confidence,

#             treatment_id=(
#                 treatment.id
#                 if treatment
#                 else None
#             ),

#             gemini_model=diagnosis.model,

#             raw_response=diagnosis.raw_response,

#         )

#         try:

#             self.db.add(history)

#             self.db.commit()

#             self.db.refresh(history)

#             return history

#         except Exception:

#             self.db.rollback()

#             raise
#     # --------------------------------------------------
#     # Helpers
#     # --------------------------------------------------

#     @staticmethod
#     def best_treatment(
#         treatments: list[TreatmentMapping],
#     ) -> TreatmentMapping | None:

#         if not treatments:

#             return None

#         if not treatments:
#             return None

#         return sorted(
#             treatments,
#             key=lambda x: (
#                 x.chemical is None,
#                 x.dosage is None,
#                 x.sms_en is None,
#             ),
#         )[0]
    
#         # --------------------------------------------------
#     # Diagnosis Pipeline
#     # --------------------------------------------------

#     def diagnose(
#         self,
#         image_path: str | Path,
#     ) -> dict:

#         # ---------------------------------------
#         # Save uploaded image
#         # ---------------------------------------

#         stored_image = self.save_image(
#             image_path
#         )

#         # ---------------------------------------
#         # Gemini Diagnosis
#         # ---------------------------------------

#         diagnosis = self.gemini.diagnose(
#             stored_image
#         )

#         # ---------------------------------------
#         # Master Label
#         # ---------------------------------------

#         label = self.get_label(
#             diagnosis.label
#         )

#         # ---------------------------------------
#         # Treatments
#         # ---------------------------------------

#         treatments = self.get_treatments(
#             class_id=label.class_id,
#             crop=diagnosis.crop,
#         )

#         treatment = self.best_treatment(
#             treatments
#         )

#         # ---------------------------------------
#         # Save History
#         # ---------------------------------------

#         history = self.save_history(
#             image_path=str(stored_image),
#             diagnosis=diagnosis,
#             treatment=treatment,
#             class_id=label.class_id,
#         )

#         # ---------------------------------------
#         # Response
#         # ---------------------------------------

#         return self._build_response(
#             history=history,
#             diagnosis=diagnosis,
#             label=label,
#             treatments=treatments,
#             stored_image=stored_image,
#         )

#     # --------------------------------------------------
#     # Response Builder
#     # --------------------------------------------------

#     def _build_response(
#         self,
#         history: DiagnosisHistory,
#         diagnosis: DiagnosisResult,
#         label: ProtectionLabel,
#         treatments: list[TreatmentMapping],
#         stored_image: Path,
#     ) -> dict:

#         recommendations = []

#         for item in treatments:

#             recommendations.append(

#                 {

#                     "id": item.id,

#                     "crop": {
#                         "en": item.crop_en,
#                         "bn": item.crop_bn,
#                     },

#                     "problem_type": {
#                         "en": item.problem_type_en,
#                         "bn": item.problem_type_bn,
#                     },

#                     "chemical": item.chemical,

#                     "chemical_type": item.chemical_type,

#                     "dosage": item.dosage,

#                     "sms": {
#                         "en": item.sms_en,
#                         "bn": item.sms_bn,
#                     },

#                 }

#             )

#         return {

#             "success": True,

#             "history_id": history.id,

#             "image": str(stored_image),

#             "diagnosis": {

#                 "class_id": label.class_id,

#                 "confidence": diagnosis.confidence,

#                 "crop": {

#                     "en": diagnosis.crop,

#                     "bn": (
#                         treatments[0].crop_bn
#                         if treatments
#                         else None
#                     ),

#                 },

#                 "problem": {

#                     "en": label.label_name_en,

#                     "bn": label.label_name_bn,

#                 },

#                 "category": {

#                     "en": label.primary_category_en,

#                     "bn": label.primary_category_bn,

#                 },

#                 "gemini_model": diagnosis.model,

#             },

#             "recommendations": recommendations,

#         }
    

#     # --------------------------------------------------
#     # Utility Methods
#     # --------------------------------------------------

#     def get_history(
#         self,
#         history_id: int,
#     ) -> DiagnosisHistory | None:

#         return (
#             self.db.query(
#                 DiagnosisHistory
#             )
#             .filter(
#                 DiagnosisHistory.id == history_id
#             )
#             .first()
#         )

#     def get_histories(
#         self,
#         limit: int = 50,
#     ) -> list[DiagnosisHistory]:

#         return (
#             self.db.query(
#                 DiagnosisHistory
#             )
#             .order_by(
#                 DiagnosisHistory.created_at.desc()
#             )
#             .limit(limit)
#             .all()
#         )

#     def delete_history(
#         self,
#         history_id: int,
#     ) -> bool:

#         history = self.get_history(
#             history_id
#         )

#         if history is None:
#             return False

#         try:

#             image_path = Path(
#                 history.image_path
#             )

#             if image_path.exists():

#                 image_path.unlink()

#         except Exception:

#             pass

#         self.db.delete(history)

#         self.db.commit()

#         return True

#     # --------------------------------------------------
#     # Health Check
#     # --------------------------------------------------

#     def health(self):

#         database = "connected"

#         gemini = "connected"

#         try:

#             self.db.execute("SELECT 1")

#         except Exception:

#             database = "disconnected"

#         try:

#             self.gemini.test_connection()

#         except Exception:

#             gemini = "disconnected"

#         return {

#             "success": database == "connected"
#             and gemini == "connected",

#             "database": database,

#             "gemini": gemini,

#             "model": self.gemini.model,

#         }

#     # --------------------------------------------------
#     # Statistics
#     # --------------------------------------------------

#     def statistics(self) -> dict:

#         total_labels = (
#             self.db.query(
#                 ProtectionLabel
#             )
#             .count()
#         )

#         total_treatments = (
#             self.db.query(
#                 TreatmentMapping
#             )
#             .count()
#         )

#         total_diagnosis = (
#             self.db.query(
#                 DiagnosisHistory
#             )
#             .count()
#         )

#         return {

#             "labels": total_labels,

#             "treatments": total_treatments,

#             "diagnosis_history": total_diagnosis,

#         }