from django.db import models
from django.utils.translation import gettext_lazy as _


class TransportType(models.TextChoices):
    TGV = "TGV", _("TGV")
    TER = "TER", _("TER")
    INTERCITES = "IC", _("Intercités")
    TRANSILIEN = "TN", _("Transilien")


class LocationType(models.IntegerChoices):
    STOP_PLATFORM = 0, _("Stop/platform")
    STATION = 1, _("Station")
    ENTRANCE_EXIT = 2, _("Entrance/exit")
    GENERIC_NODE = 3, _("Generic node")
    BOARDING_AREA = 4, _("Boarding area")


class AccessInformation(models.IntegerChoices):
    NO_INFORMATION = 0, _("No information")
    POSSIBLE = 1, _("Possible")
    NOT_POSSIBLE = 2, _("Not possible")


class PickupType(models.IntegerChoices):
    REGULAR = 0, _("Regular")
    NONE = 1, _("None")
    MUST_PHONE_AGENCY = 2, _("Must phone agency")
    MUST_COORDINATE_WITH_DRIVER = 3, _("Must coordinate with driver")


class RouteType(models.IntegerChoices):
    TRAM = 0, _("Tram")
    METRO = 1, _("Metro")
    RAIL = 2, _("Rail")
    BUS = 3, _("Bus")
    FERRY = 4, _("Ferry")
    CABLE_CAR = 5, _("Cable car")
    GONDOLA = 6, _("Gondola")
    FUNICULAR = 7, _("Funicular")


class Direction(models.IntegerChoices):
    OUTBOUND = 0, _("Outbound")
    INBOUND = 1, _("Inbound")


class TransferType(models.IntegerChoices):
    RECOMMENDED = 0, _("Recommended")
    TIMED = 1, _("Timed")
    MINIMUM_TIME = 2, _("Minimum time")
    NOT_POSSIBLE = 3, _("Not possible")


class ExceptionType(models.IntegerChoices):
    ADDED = 1, _("Added")
    REMOVED = 2, _("Removed")


class Agency(models.Model):
    id = models.CharField(
        max_length=255,
        primary_key=True,
        verbose_name=_("Agency ID"),
    )

    name = models.CharField(
        max_length=255,
        unique=True,
        verbose_name=_("Agency name"),
    )

    url = models.URLField(
        verbose_name=_("Agency URL"),
    )

    timezone = models.CharField(
        max_length=255,
        verbose_name=_("Agency timezone"),
    )

    lang = models.CharField(
        max_length=255,
        verbose_name=_("Agency language"),
        blank=True,
    )

    phone = models.CharField(
        max_length=255,
        verbose_name=_("Agency phone"),
        blank=True,
    )

    email = models.EmailField(
        verbose_name=_("Agency email"),
        blank=True,
    )

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = _("Agency")
        verbose_name_plural = _("Agencies")
        ordering = ("name",)


class Stop(models.Model):
    id = models.CharField(
        max_length=255,
        primary_key=True,
        verbose_name=_("Stop ID"),
    )

    code = models.CharField(
        max_length=255,
        verbose_name=_("Stop code"),
        blank=True,
    )

    name = models.CharField(
        max_length=255,
        verbose_name=_("Stop name"),
    )

    desc = models.CharField(
        max_length=255,
        verbose_name=_("Stop description"),
        blank=True,
    )

    lon = models.FloatField(
        verbose_name=_("Stop longitude"),
    )

    lat = models.FloatField(
        verbose_name=_("Stop latitude"),
    )

    zone_id = models.CharField(
        max_length=255,
        verbose_name=_("Zone ID"),
    )

    url = models.URLField(
        verbose_name=_("Stop URL"),
        blank=True,
    )

    location_type = models.IntegerField(
        verbose_name=_("Location type"),
        blank=True,
        choices=LocationType,
        default=LocationType.STOP_PLATFORM,
    )

    parent_station = models.ForeignKey(
        to="Stop",
        on_delete=models.PROTECT,
        verbose_name=_("Parent station"),
        related_name="children",
        blank=True,
        null=True,
    )

    timezone = models.CharField(
        max_length=255,
        verbose_name=_("Stop timezone"),
        blank=True,
    )

    level_id = models.CharField(
        max_length=255,
        verbose_name=_("Level ID"),
        blank=True,
    )

    wheelchair_boarding = models.IntegerField(
        verbose_name=_("Wheelchair boarding"),
        blank=True,
        choices=AccessInformation,
        default=AccessInformation.NO_INFORMATION,
    )

    platform_code = models.CharField(
        max_length=255,
        verbose_name=_("Platform code"),
        blank=True,
    )

    def __str__(self):
        return f"{self.name} ({self.id})"

    class Meta:
        verbose_name = _("Stop")
        verbose_name_plural = _("Stops")
        ordering = ("id",)


class Route(models.Model):
    id = models.CharField(
        max_length=255,
        primary_key=True,
        verbose_name=_("ID"),
    )

    agency = models.ForeignKey(
        to="Agency",
        on_delete=models.CASCADE,
        verbose_name=_("Agency ID"),
        related_name="routes",
    )

    short_name = models.CharField(
        max_length=255,
        verbose_name=_("Route short name"),
    )

    long_name = models.CharField(
        max_length=255,
        verbose_name=_("Route long name"),
    )

    desc = models.CharField(
        max_length=255,
        verbose_name=_("Route description"),
        blank=True,
    )

    type = models.IntegerField(
        verbose_name=_("Route type"),
        choices=RouteType,
    )

    url = models.URLField(
        verbose_name=_("Route URL"),
        blank=True,
    )

    color = models.CharField(
        max_length=255,
        verbose_name=_("Route color"),
        blank=True,
    )

    text_color = models.CharField(
        max_length=255,
        verbose_name=_("Route text color"),
        blank=True,
    )

    def __str__(self):
        return f"{self.long_name}"

    class Meta:
        verbose_name = _("Route")
        verbose_name_plural = _("Routes")
        ordering = ("id",)


class Trip(models.Model):
    id = models.CharField(
        max_length=255,
        primary_key=True,
        verbose_name=_("Trip ID"),
    )

    route = models.ForeignKey(
        to="Route",
        on_delete=models.CASCADE,
        verbose_name=_("Route"),
        related_name="trips",
    )

    service = models.ForeignKey(
        to="Calendar",
        on_delete=models.CASCADE,
        verbose_name=_("Service"),
        related_name="trips",
    )

    headsign = models.CharField(
        max_length=255,
        verbose_name=_("Trip headsign"),
        blank=True,
    )

    short_name = models.CharField(
        max_length=255,
        verbose_name=_("Trip short name"),
        blank=True,
    )

    direction_id = models.IntegerField(
        verbose_name=_("Direction"),
        choices=Direction,
        null=True,
    )

    block_id = models.CharField(
        max_length=255,
        verbose_name=_("Block ID"),
        blank=True,
    )

    shape_id = models.CharField(
        max_length=255,
        verbose_name=_("Shape ID"),
        blank=True,
    )

    wheelchair_accessible = models.IntegerField(
        verbose_name=_("Wheelchair accessible"),
        choices=AccessInformation,
        default=AccessInformation.NO_INFORMATION,
        null=True,
    )

    bikes_allowed = models.IntegerField(
        verbose_name=_("Bikes allowed"),
        choices=AccessInformation,
        default=AccessInformation.NO_INFORMATION,
        null=True,
    )

    @property
    def origin(self):
        return self.stop_times.order_by('stop_sequence').first().stop

    @property
    def destination(self):
        return self.stop_times.order_by('-stop_sequence').first().stop

    @property
    def train_type(self):
        if self.service.transport_type == TransportType.TRANSILIEN:
            return self.route.short_name
        else:
            train_type = self.origin.id.split('StopPoint:OCE')[1].split('-')[0]
            if train_type == "Train TER":
                train_type = "TER"
            elif train_type == "INTERCITES":
                train_type = "INTER-CITÉS"
            elif train_type == "INTERCITES de nuit":
                train_type = "INTER-CITÉS de nuit"
        return train_type

    @property
    def train_number(self):
        if self.service.transport_type == TransportType.TRANSILIEN:
            return self.short_name
        else:
            return self.headsign

    @property
    def color(self):
        if self.route.color:
            return self.route.color
        elif self.train_type == "OUIGO":
            return "E60075"
        return "FFFFFF"

    @property
    def text_color(self):
        if self.route.text_color:
            return self.route.text_color
        elif self.train_type == "OUIGO":
            return "FFFFFF"
        elif self.train_type == "TGV INOUI":
            return "9B2743"
        elif self.train_type == "INTER-CITÉS" or self.train_type == "INTER-CITÉS de nuit":
            return "404042"
        return "000000"

    def __str__(self):
        return f"{self.route.long_name} - {self.id}"

    class Meta:
        verbose_name = _("Trip")
        verbose_name_plural = _("Trips")
        ordering = ("id",)


class StopTime(models.Model):
    id = models.CharField(
        max_length=255,
        primary_key=True,
        verbose_name=_("ID"),
    )

    trip = models.ForeignKey(
        to="Trip",
        on_delete=models.CASCADE,
        verbose_name=_("Trip"),
        related_name="stop_times",
    )

    arrival_time = models.DurationField(
        verbose_name=_("Arrival time"),
    )

    departure_time = models.DurationField(
        verbose_name=_("Departure time"),
    )

    stop = models.ForeignKey(
        to="Stop",
        on_delete=models.CASCADE,
        verbose_name=_("Stop ID"),
        related_name="stop_times",
    )

    stop_sequence = models.IntegerField(
        verbose_name=_("Stop sequence"),
    )

    stop_headsign = models.CharField(
        max_length=255,
        verbose_name=_("Stop headsign"),
        blank=True,
    )

    pickup_type = models.IntegerField(
        verbose_name=_("Pickup type"),
        choices=PickupType,
        default=PickupType.REGULAR,
        null=True,
    )

    drop_off_type = models.IntegerField(
        verbose_name=_("Drop off type"),
        choices=PickupType,
        default=PickupType.REGULAR,
        null=True,
    )

    timepoint = models.BooleanField(
        verbose_name=_("Timepoint"),
        default=True,
        null=True,
    )

    @property
    def pretty_arrival_time(self):
        seconds = self.arrival_time.total_seconds()
        hours = int(seconds // 3600) % 24
        minutes = int((seconds % 3600) // 60)
        return f"{hours:02}:{minutes:02}"

    @property
    def pretty_departure_time(self):
        seconds = self.departure_time.total_seconds()
        hours = int(seconds // 3600) % 24
        minutes = int((seconds % 3600) // 60)
        return f"{hours:02}:{minutes:02}"

    def __str__(self):
        return f"{self.trip.route.long_name} - {self.trip_id} - {self.stop.name}"

    class Meta:
        verbose_name = _("Stop time")
        verbose_name_plural = _("Stop times")


class Calendar(models.Model):
    id = models.CharField(
        max_length=255,
        primary_key=True,
        verbose_name=_("Service ID"),
    )

    monday = models.BooleanField(
        verbose_name=_("Monday"),
    )

    tuesday = models.BooleanField(
        verbose_name=_("Tuesday"),
    )

    wednesday = models.BooleanField(
        verbose_name=_("Wednesday"),
    )

    thursday = models.BooleanField(
        verbose_name=_("Thursday"),
    )

    friday = models.BooleanField(
        verbose_name=_("Friday"),
    )

    saturday = models.BooleanField(
        verbose_name=_("Saturday"),
    )

    sunday = models.BooleanField(
        verbose_name=_("Sunday"),
    )

    start_date = models.DateField(
        verbose_name=_("Start date"),
    )

    end_date = models.DateField(
        verbose_name=_("End date"),
    )

    transport_type = models.CharField(
        max_length=255,
        verbose_name=_("Transport type"),
        choices=TransportType,
    )

    def __str__(self):
        return self.id

    class Meta:
        verbose_name = _("Calendar")
        verbose_name_plural = _("Calendars")
        ordering = ("id",)


class CalendarDate(models.Model):
    id = models.CharField(
        max_length=255,
        primary_key=True,
        verbose_name=_("ID"),
    )

    service = models.ForeignKey(
        to="Calendar",
        on_delete=models.CASCADE,
        verbose_name=_("Service"),
        related_name="dates",
    )

    date = models.DateField(
        verbose_name=_("Date"),
    )

    exception_type = models.IntegerField(
        verbose_name=_("Exception type"),
        choices=ExceptionType,
    )

    transport_type = models.CharField(
        max_length=255,
        verbose_name=_("Transport type"),
        choices=TransportType,
    )

    def __str__(self):
        return f"{self.service.id} - {self.date} - {self.exception_type}"

    class Meta:
        verbose_name = _("Calendar date")
        verbose_name_plural = _("Calendar dates")
        ordering = ("id",)


class Transfer(models.Model):
    id = models.CharField(
        max_length=255,
        primary_key=True,
        verbose_name=_("ID"),
    )

    from_stop = models.ForeignKey(
        to="Stop",
        on_delete=models.CASCADE,
        verbose_name=_("From stop"),
        related_name="transfers_from",
    )

    to_stop = models.ForeignKey(
        to="Stop",
        on_delete=models.CASCADE,
        verbose_name=_("To stop"),
        related_name="transfers_to",
    )

    transfer_type = models.IntegerField(
        verbose_name=_("Transfer type"),
        choices=TransferType,
        default=TransferType.RECOMMENDED,
    )

    min_transfer_time = models.IntegerField(
        verbose_name=_("Minimum transfer time"),
        blank=True,
    )

    class Meta:
        verbose_name = _("Transfer")
        verbose_name_plural = _("Transfers")
        ordering = ("id",)


class FeedInfo(models.Model):
    publisher_name = models.CharField(
        max_length=255,
        verbose_name=_("Feed publisher name"),
    )

    publisher_url = models.URLField(
        verbose_name=_("Feed publisher URL"),
    )

    lang = models.CharField(
        max_length=255,
        verbose_name=_("Feed language"),
    )

    start_date = models.DateField(
        verbose_name=_("Feed start date"),
    )

    end_date = models.DateField(
        verbose_name=_("Feed end date"),
    )

    version = models.CharField(
        max_length=255,
        verbose_name=_("Feed version"),
    )

    class Meta:
        verbose_name = _("Feed info")
        verbose_name_plural = _("Feed infos")
        ordering = ("publisher_name",)
