text: from datetime import timedelta
  
  from django.core.validators import MaxValueValidator, MinValueValidator
  from django.db import models
  from django.urls.base import reverse
  from django.utils import formats
  from django.utils.functional import cached_property
  
  from .common import CommonInfo
  
  
  class Session(CommonInfo):
      from .course import Course
      from .location import Location
      from .mentor import Mentor
      from .student import Student
  
      MALE = "male"
      FEMALE = "female"
  
      GENDER_LIMITATION_CHOICES = (
          (MALE, "Male"),
          (FEMALE, "Female"),
      )
  
      course = models.ForeignKey(
          Course,
          on_delete=models.CASCADE,
          limit_choices_to={"is_active": True},
      )
      start_date = models.DateTimeField()
      location = models.ForeignKey(
          Location,
          on_delete=models.CASCADE,
          limit_choices_to={"is_active": True},
      )
      capacity = models.IntegerField(
          default=20,
      )
      mentor_capacity = models.IntegerField(
          default=10,
      )
      instructor = models.ForeignKey(
          Mentor,
          on_delete=models.CASCADE,
          related_name="session_instructor",
          limit_choices_to={
              "user__groups__name": "Instructor",
              "is_active": True,
              "user__is_active": True,
              "background_check": True,
              "avatar_approved": True,
          },
          help_text="A mentor with 'Instructor' role, is active (user and mentor), background check passed, and avatar approved.",
      )
  
      assistant = models.ManyToManyField(
          Mentor,
          blank=True,
          related_name="session_assistant",
          limit_choices_to={
              "user__groups__name": "Assistant",
              "is_active": True,
              "user__is_active": True,
              "background_check": True,
              "avatar_approved": True,
          },
          help_text="A mentor with 'Assistant' role, is active (user and mentor), background check passed, and avatar approved.",
      )
  
      # Pricing
      cost = models.DecimalField(
          max_digits=6,
          decimal_places=2,
          blank=True,
          null=True,
      )
      minimum_cost = models.DecimalField(
          max_digits=6,
          decimal_places=2,
          blank=True,
          null=True,
      )
      maximum_cost = models.DecimalField(
          max_digits=6,
          decimal_places=2,
          blank=True,
          null=True,
      )
  
      # Extra
      additional_info = models.TextField(blank=True, null=True, help_text="Basic HTML allowed")
      waitlist_mentors = models.ManyToManyField(
          Mentor,
          blank=True,
          related_name="session_waitlist_mentors",
      )
      waitlist_students = models.ManyToManyField(
          Student,
          blank=True,
          related_name="session_waitlist_students",
      )
      external_enrollment_url = models.CharField(
          max_length=255,
          blank=True,
          null=True,
          help_text="When provided, local enrollment is disabled.",
      )
  
      is_active = models.BooleanField(
          default=False,
          help_text="Session is active.",
      )
      is_public = models.BooleanField(
          default=False,
          help_text="Session is a public session.",
      )
      password = models.CharField(
          blank=True,
          max_length=255,
      )
      partner_message = models.TextField(
          blank=True,
      )
      announced_date_mentors = models.DateTimeField(
          blank=True,
          null=True,
      )
      announced_date_guardians = models.DateTimeField(
          blank=True,
          null=True,
      )
      image_url = models.CharField(
          max_length=255,
          blank=True,
          null=True,
      )
      bg_image = models.ImageField(
          blank=True,
          null=True,
      )
      mentors_week_reminder_sent = models.BooleanField(
          default=False,
      )
      mentors_day_reminder_sent = models.BooleanField(
          default=False,
      )
      gender_limitation = models.CharField(
          help_text="Limits the class to be only one gender.",
          max_length=255,
          choices=GENDER_LIMITATION_CHOICES,
          blank=True,
          null=True,
      )
      override_minimum_age_limitation = models.IntegerField(
          "Min Age",
          help_text="Only update this if different from the default.",
          blank=True,
          null=True,
          validators=[MinValueValidator(0), MaxValueValidator(100)],
      )
      override_maximum_age_limitation = models.IntegerField(
          "Max Age",
          help_text="Only update this if different from the default.",
          blank=True,
          null=True,
          validators=[MinValueValidator(0), MaxValueValidator(100)],
      )
      online_video_link = models.URLField(
          "Online Video Link",
          help_text="Zoom link with password.",
          blank=True,
          null=True,
      )
      online_video_meeting_id = models.CharField(
          "Online Video Meeting ID",
          help_text="XXX XXXX XXXX",
          max_length=255,
          blank=True,
          null=True,
      )
      online_video_meeting_password = models.CharField(
          "Online Video Meeting Password",
          help_text="Plain text password shared by Zoom",
          max_length=255,
          blank=True,
          null=True,
      )
      online_video_description = models.TextField(
          "Online Video Description",
          help_text="Information on how to connect to the video call. Basic HTML allowed.",
          blank=True,
          null=True,
      )
  
      # kept for older records
      old_end_date = models.DateTimeField(
          blank=True,
          null=True,
      )
      old_mentor_start_date = models.DateTimeField(
          blank=True,
          null=True,
      )
      old_mentor_end_date = models.DateTimeField(
          blank=True,
          null=True,
      )
  
      @property
      def end_date(self):
          # Some records have a defined record with the end date,
          # rather than use the course's duration.
          # We're keeping this for old records.
          if self.old_end_date:
              return self.old_end_date
  
          return self.start_date + self.course.duration
  
      @property
      def mentor_start_date(self):
          # Some records have a defined record with the mentor start date,
          # rather than do the math.
          # We're keeping this for old records.
          if self.old_mentor_start_date:
              return self.old_mentor_start_date
  
          return self.start_date - timedelta(hours=1)
  
      @property
      def mentor_end_date(self):
          # Some records have a defined record with the mentor start date,
          # rather than do the math.
          # We're keeping this for old records.
          if self.old_mentor_end_date:
              return self.old_mentor_end_date
  
          return self.end_date + timedelta(hours=1)
  
      @property
      def minimum_age(self):
          if self.override_minimum_age_limitation is not None:
              return self.override_minimum_age_limitation
  
          return self.course.minimum_age
  
      @property
      def maximum_age(self):
          if self.override_maximum_age_limitation is not None:
              return self.override_maximum_age_limitation
  
          return self.course.maximum_age
  
      def __str__(self):
          date = formats.date_format(self.start_date, "SHORT_DATETIME_FORMAT")
          return f"{self.course.title} | {date}"
  
      def save(self, *args, **kwargs):
  
          # Mentor Capacity Check
          if self.mentor_capacity is None:
              self.mentor_capacity = int(self.capacity / 2)
  
          if self.mentor_capacity < 0:
              self.mentor_capacity = 0
  
          # Capacity check
          if self.capacity < 0:
              self.capacity = 0
  
          super(Session, self).save(*args, **kwargs)
  
      def get_absolute_url(self) -> str:
          return reverse("session-detail", args=[str(self.id)])
  
      def get_sign_up_url(self):
          return reverse("session-sign-up", args=[str(self.id)])
  
      def get_calendar_url(self):
          return reverse("session-calendar", args=[str(self.id)])
  
      def is_guardian_announced(self):
          return self.announced_date_guardians is not None
  
      is_guardian_announced.boolean = True
      is_guardian_announced.short_description = "Is Announced"
      is_guardian_announced.admin_order_field = "announced_date_guardians"
  
      def get_mentor_orders(self):
          from .mentor_order import MentorOrder
  
          return MentorOrder.objects.filter(
              session=self,
              is_active=True,
          ).order_by("mentor__user__last_name")
  
      def get_checked_in_mentor_orders(self):
          from .mentor_order import MentorOrder
  
          return MentorOrder.objects.filter(session=self, is_active=True, check_in__isnull=False).order_by(
              "mentor__user__last_name"
          )
  
      def get_current_orders(self, checked_in=None):
          from .order import Order
  
          if checked_in is not None:
              if checked_in:
                  orders = (
                      Order.objects.filter(is_active=True, session=self)
                      .exclude(check_in=None)
                      .order_by("student__last_name")
                  )
              else:
                  orders = Order.objects.filter(is_active=True, session=self, check_in=None).order_by(
                      "student__last_name"
                  )
          else:
              orders = Order.objects.filter(is_active=True, session=self).order_by("check_in", "student__last_name")
  
          return orders
  
      def get_active_student_count(self):
          from .order import Order
  
          return Order.objects.filter(is_active=True, session=self).values("student").count()
  
      def get_checked_in_students(self):
          from .order import Order
  
          return Order.objects.filter(is_active=True, session=self).exclude(check_in=None).values("student")
  
  
  class PartnerPasswordAccess(CommonInfo):
      from .user import CDCUser
  
      user = models.ForeignKey(
          CDCUser,
          on_delete=models.CASCADE,
      )
      session = models.ForeignKey(
          Session,
          on_delete=models.CASCADE,
      )
  
      class Meta:
          db_table = "partner_password_access"
  