"""Logic for c) Estrategias y procedimientos de evaluación: eval_diversity_types, course_eval_diversity, observations."""

from datetime import datetime
from typing import Optional, Any, List
from sqlalchemy.orm import Session
from app.backend.db.models import (
    EvalDiversityTypeModel,
    CourseEvalDiversityModel,
    CourseEvalDiversityObservationModel,
)


def _serialize_date(v):
    if v is None:
        return None
    if hasattr(v, "isoformat"):
        return v.isoformat()
    return str(v) if v else None


def _eval_to_dict(r: CourseEvalDiversityModel) -> dict:
    return {
        "id": r.id,
        "course_id": r.course_id,
        "eval_diversity_type_id": r.eval_diversity_type_id,
        "strategies_text": r.strategies_text,
        "added_date": _serialize_date(r.added_date),
        "updated_date": _serialize_date(r.updated_date),
        "deleted_date": _serialize_date(r.deleted_date),
    }


class CourseEvalDiversityClass:
    def __init__(self, db: Session):
        self.db = db

    def get_types(self) -> Any:
        """List eval diversity types (deleted_date is None), ordered by sort_order."""
        try:
            rows = (
                self.db.query(EvalDiversityTypeModel)
                .filter(EvalDiversityTypeModel.deleted_date.is_(None))
                .order_by(EvalDiversityTypeModel.sort_order)
                .all()
            )
            return {
                "status": "success",
                "data": [
                    {"id": r.id, "key": r.key, "label": r.label, "sort_order": r.sort_order}
                    for r in rows
                ],
            }
        except Exception as e:
            return {"status": "error", "message": str(e), "data": []}

    def get_by_course_id(self, course_id: int) -> Any:
        """Full structure for the course: each type with its row (strategies_text) and observations."""
        try:
            types_rows = (
                self.db.query(EvalDiversityTypeModel)
                .filter(EvalDiversityTypeModel.deleted_date.is_(None))
                .order_by(EvalDiversityTypeModel.sort_order)
                .all()
            )
            evals = (
                self.db.query(CourseEvalDiversityModel)
                .filter(
                    CourseEvalDiversityModel.course_id == course_id,
                    CourseEvalDiversityModel.deleted_date.is_(None),
                )
                .all()
            )
            eval_by_type = {e.eval_diversity_type_id: e for e in evals}
            obs_row = (
                self.db.query(CourseEvalDiversityObservationModel)
                .filter(
                    CourseEvalDiversityObservationModel.course_id == course_id,
                    CourseEvalDiversityObservationModel.deleted_date.is_(None),
                )
                .first()
            )
            observations = obs_row.observations if obs_row else None
            result = []
            for t in types_rows:
                e = eval_by_type.get(t.id)
                result.append({
                    "type": {"id": t.id, "key": t.key, "label": t.label, "sort_order": t.sort_order},
                    "eval": _eval_to_dict(e) if e else None,
                    "strategies_text": e.strategies_text if e else None,
                })
            return {"status": "success", "data": result, "observations": observations}
        except Exception as e:
            return {"status": "error", "message": str(e), "data": [], "observations": None}

    def get_by_id(self, id: int) -> Any:
        """Get one course_eval_diversity by id."""
        try:
            row = (
                self.db.query(CourseEvalDiversityModel)
                .filter(CourseEvalDiversityModel.id == id)
                .first()
            )
            if not row:
                return {"status": "error", "message": "Registro no encontrado.", "data": None}
            return {"status": "success", "data": _eval_to_dict(row)}
        except Exception as e:
            return {"status": "error", "message": str(e), "data": None}

    def get_observations(self, course_id: int) -> Any:
        """Get observations for the course (section c)."""
        try:
            row = (
                self.db.query(CourseEvalDiversityObservationModel)
                .filter(
                    CourseEvalDiversityObservationModel.course_id == course_id,
                    CourseEvalDiversityObservationModel.deleted_date.is_(None),
                )
                .first()
            )
            return {"status": "success", "data": {"observations": row.observations if row else None}}
        except Exception as e:
            return {"status": "error", "message": str(e), "data": None}

    def set_observations(self, course_id: int, observations: Optional[str]) -> Any:
        """Create or update observations for the course (one row per course_id)."""
        try:
            row = (
                self.db.query(CourseEvalDiversityObservationModel)
                .filter(CourseEvalDiversityObservationModel.course_id == course_id)
                .first()
            )
            now = datetime.now()
            text = (observations or "").strip() if observations is not None else ""
            if row:
                row.observations = text or None
                row.updated_date = now
                row.deleted_date = None
            else:
                self.db.add(CourseEvalDiversityObservationModel(
                    course_id=course_id,
                    observations=text or None,
                    added_date=now,
                    updated_date=now,
                    deleted_date=None,
                ))
            self.db.commit()
            return {"status": "success", "message": "Observaciones guardadas."}
        except Exception as e:
            self.db.rollback()
            return {"status": "error", "message": str(e)}

    def store(self, data: dict) -> Any:
        """Create or update one eval diversity row by (course_id, eval_diversity_type_id). Optionally save observations."""
        try:
            course_id = data.get("course_id")
            eval_diversity_type_id = data.get("eval_diversity_type_id")
            if course_id is None or eval_diversity_type_id is None:
                return {"status": "error", "message": "course_id y eval_diversity_type_id son requeridos."}
            course_id = int(course_id)
            eval_diversity_type_id = int(eval_diversity_type_id)
            strategies_text = (data.get("strategies_text") or "").strip() or None
            now = datetime.now()

            row = (
                self.db.query(CourseEvalDiversityModel)
                .filter(
                    CourseEvalDiversityModel.course_id == course_id,
                    CourseEvalDiversityModel.eval_diversity_type_id == eval_diversity_type_id,
                )
                .first()
            )
            if row:
                row.strategies_text = strategies_text
                row.updated_date = now
                row.deleted_date = None
                self.db.commit()
                self.db.refresh(row)
                response_id = row.id
                msg = "Registro actualizado."
            else:
                row = CourseEvalDiversityModel(
                    course_id=course_id,
                    eval_diversity_type_id=eval_diversity_type_id,
                    strategies_text=strategies_text,
                    added_date=now,
                    updated_date=now,
                    deleted_date=None,
                )
                self.db.add(row)
                self.db.commit()
                self.db.refresh(row)
                response_id = row.id
                msg = "Registro creado."

            if "observations" in data:
                self.set_observations(course_id, data.get("observations"))
            return {"status": "success", "message": msg, "id": response_id, "data": _eval_to_dict(row)}
        except Exception as e:
            self.db.rollback()
            return {"status": "error", "message": str(e)}

    def update(self, id: int, data: dict) -> Any:
        """Update one course_eval_diversity by id (optional: strategies_text)."""
        try:
            row = self.db.query(CourseEvalDiversityModel).filter(CourseEvalDiversityModel.id == id).first()
            if not row:
                return {"status": "error", "message": "Registro no encontrado."}
            if "strategies_text" in data:
                row.strategies_text = (data["strategies_text"] or "").strip() or None
            row.updated_date = datetime.now()
            self.db.commit()
            self.db.refresh(row)
            return {"status": "success", "message": "Registro actualizado.", "id": id, "data": _eval_to_dict(row)}
        except Exception as e:
            self.db.rollback()
            return {"status": "error", "message": str(e)}

    def delete(self, id: int) -> Any:
        """Soft delete (deleted_date)."""
        try:
            row = self.db.query(CourseEvalDiversityModel).filter(CourseEvalDiversityModel.id == id).first()
            if not row:
                return {"status": "error", "message": "Registro no encontrado."}
            row.deleted_date = datetime.now()
            row.updated_date = row.deleted_date
            self.db.commit()
            return {"status": "success", "message": "Registro eliminado.", "id": id}
        except Exception as e:
            self.db.rollback()
            return {"status": "error", "message": str(e)}
