from rest_framework import status
from rest_framework.exceptions import ValidationError

from api.models import EsExamPeriod, EsSessionStart
from api.models import EsSuitability
from api.models.es_exam_activity import EsExamActivity
from api.models.es_exam_requirement import EsExamRequirement
from api.models.es_location import EsLocation
from api.models.es_session import EsSession
from api.translation import __
from api.utils import log_critical_error, get_exception_detail
from api.validator import BaseValidator
from api.views.admin.base import AdminApiBase


class ExamActivityRules(AdminApiBase):
	@staticmethod
	def build_session_start_data(session_start):
		data = {
			"id": session_start.id,
			"code": session_start.code,
			"start_time": session_start.start_time,
			"status": session_start.status,
			"status_text": __("attr.session_start_status." + str(session_start.status)),
		}
		days = [
			{
				"id": rp.day,
				"name": __("attr.days_name." + str(rp.day)),
			}
			for rp in session_start.essessionstartday_set.order_by("day").all()
		]
		data["days"] = days

		for i in range(1, 11):
			extra_data_field = f"extra_data_{i}"
			data[extra_data_field] = getattr(session_start, extra_data_field, None)

		return data

	def validate_request(self, request):
		rules = {
			"id": "nullable|array|exists:api.EsExamActivity,id",
		}

		attribute = {}

		validator = BaseValidator(request.data, rules, attribute)
		error = validator.validate()
		if error:
			raise ValidationError(error)

	def post(self, request):
		try:
			self.api_log_skip_outgoing_data = True
			self.validate_request(request)

			ids = request.data.get("id")
			if not ids:
				ids = []
			obj = None
			if isinstance(ids, (list, tuple)) and len(ids) == 1:
				obj = (
					EsExamActivity.objects
					.select_related("exam_requirement", "session")
					.prefetch_related("invigilator_suitability", "location_suitability")
					.filter(id__in=ids)
					.first()
				)

			info = None
			if obj:
				info = {}
				info["id"] = obj.id
				info["exam_requirement_id"] = obj.exam_requirement_id
				info["location_id"] = obj.location_id
				info["location"] = obj.location.name if obj.location else None
				info["session_id"] = obj.session_id
				info["session"] = obj.session.name if obj.session else None
				info["code"] = obj.code
				info["name"] = obj.name
				info["time_slot"] = obj.time_slot
				info["is_scheduled"] = obj.is_scheduled
				info["invigilator_suitability"] = obj.invigilator_suitability.all().values_list("id", flat=True)
				info["location_suitability"] = obj.location_suitability.all().values_list("id", flat=True)

			data = {}
			data["delete_confirmation_api"] = False
			data["allow_remove"] = ["location_id"]
			data["location"] = [
				{
					"id": location.id,
					"code": location.code,
					"name": location.name,
				}
				for location in EsLocation.objects.filter(status=EsLocation.STATUS_TO_CODE["active"]).order_by("name").all()
			]
			data["exam_requirements"] = [
				{
					"id": req.id,
					"code": req.code,
					"name": req.name,
				}
				for req in EsExamRequirement.objects.order_by("name").all()
			]
			data["exam_periods"] = [
				{
					"id": exam_period.id,
					"code": exam_period.code,
					"name": exam_period.name,
					"session_start": [
						self.build_session_start_data(session_start)
						for session_start in exam_period.essessionstart_set.prefetch_related("essessionstartday_set").order_by("start_time", "id").all()
					],
				}
				for exam_period in EsExamPeriod.objects.filter(status=EsExamPeriod.STATUS_TO_CODE["active"]).order_by("name").all()
			]

			data["invigilator_suitability"] = []
			data["location_suitability"] = []

			selected_invigilator_suitability_ids = []
			selected_location_suitability_ids = []
			if obj:
				selected_invigilator_suitability_ids = [s.id for s in obj.invigilator_suitability.all()]
				selected_location_suitability_ids = [s.id for s in obj.location_suitability.all()]

			suitabilities = (
				EsSuitability.objects
				.filter(status=EsSuitability.STATUS_TO_CODE["active"])
				.prefetch_related("invigilator", "location")
				.order_by(self.list_default_order_column)
				.all()
			)

			for suitability in suitabilities:
				if suitability.invigilator.exists() or suitability.id in selected_invigilator_suitability_ids:
					data["invigilator_suitability"].append({
						"id": suitability.id,
						"code": suitability.code,
						"name": suitability.name,
						"items": [f"{invigilator.id} - {invigilator.name}" for invigilator in suitability.invigilator.all()],
					})

				if suitability.location.exists() or suitability.id in selected_location_suitability_ids:
					data["location_suitability"].append({
						"id": suitability.id,
						"code": suitability.code,
						"name": suitability.name,
						"items": [f"{location.id} - {location.name}" for location in suitability.location.all()],
					})

			response = {
				"info": info,
				"rules": data,
			}

			return self.api_response(data=response)
		except ValidationError as e:
			first_message = e.detail["error"]
			errors = e.detail["errors"]
			return self.api_response(error=first_message, errors=errors, code=status.HTTP_400_BAD_REQUEST)
		except Exception as e:
			e_details = get_exception_detail(e)
			log_critical_error(user_id=None, descr=e_details["descr"], url=e_details["url"], trace=e_details["trace"])
			return self.api_response(error=__("message.internal_server_error"), code=status.HTTP_500_INTERNAL_SERVER_ERROR)