from rest_framework import status
from rest_framework.exceptions import ValidationError

from api.models import EsExamPeriod
from api.models.es_exam_requirement import EsExamRequirement
from api.models import EsSuitability
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 ExamRequirementRules(AdminApiBase):
	def validate_request(self, request):
		rules = {
			"id": "nullable|array|exists:api.EsExamRequirement,id",
		}
		# if need rename field, can put here
		attribute = {
			# "email": __("attr.email"),
		}
		# validate id first, cause need get object by id, if wrong id direct return error
		validator = BaseValidator(request.data, rules, attribute)
		error = validator.validate()
		if error:
			raise ValidationError(error)

		# custom error after basic validation
		if error:
			raise ValidationError(error)

	def post(self, request):
		# Validate input
		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 = (
					EsExamRequirement.objects
					.prefetch_related("invigilator_suitability", "location_suitability")
					.filter(id__in=ids)
					.first()
				)

			info = None
			if obj:
				info = {}
				info["id"] = obj.id
				info["exam_period_id"] = obj.exam_period_id
				info["exam_period"] = obj.exam_period.name if obj.exam_period else None
				info["code"] = obj.code
				info["name"] = obj.name
				info["description"] = obj.description
				info["planned_size"] = obj.planned_size
				info["writing_time"] = obj.writing_time
				info["fixed_start_date"] = obj.fixed_start_date
				info["reading_time"] = obj.reading_time
				info["fixed_start_time"] = obj.fixed_start_time
				info["location_required"] = obj.location_required
				info["exclusive_use"] = obj.exclusive_use
				info["minimum_split_size"] = obj.minimum_split_size
				info["earliest_start"] = obj.earliest_start
				info["latest_end"] = obj.latest_end
				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"] = [
				"description",
				"location_required",
				"exclusive_use",
				"minimum_split_size",
				"fixed_start_date",
				"fixed_start_time",
				"earliest_start",
				"latest_end",
				"invigilator_suitability",
				"location_suitability",
			]
			data["exam_periods"] = [
				{
					"id": exam_period.id,
					"code": exam_period.code,
					"name": exam_period.name,
				}
				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)
