import datetime
import re
from django.urls import reverse
from django.apps import apps
from django.template.defaultfilters import slugify
from django.contrib.gis.db import models
# from django.contrib.auth.models import User
from django.utils import timezone
from django import forms
from django.conf import settings

# from photos.models import LuxImage

from locations.models import Location
from utils.widgets import parse_image
from utils.widgets import markdown_to_html
from utils.next_prev import next_in_order, prev_in_order


def render_images(s):
    s = re.sub('<img(.*)/>', parse_image, s)
    return s


def get_upload_path(self, filename):
    return "images/sightings-images/%s/%s" % (datetime.datetime.today().strftime("%Y"), filename)


# from http://aba.org/checklist/codes.html
ABA_CODES = (
    (0, 'unknown'),
    (1, 'regular occurring - common'),
    (2, 'regular occurring - less common'),
    (3, 'rare'),
    (4, 'casual'),
    (5, 'accidental'),
    (6, 'Cannot be found'),
)

KIND_LIST = (
    (1, 'Birds'),
    (2, 'Mammals'),
    (3, 'Reptiles'),
    (4, 'Amphibians'),
    (5, 'Plants'),
)


class APClass(models.Model):
    common_name = models.CharField(max_length=200)
    scientific_name = models.CharField(max_length=200)
    kind = models.IntegerField(choices=KIND_LIST, default=1)

    class Meta:
        verbose_name_plural = 'Animal/Plant Class'
        ordering = ["kind", "common_name"]

    def __str__(self):
        return self.common_name


class AP(models.Model):
    common_name = models.CharField(max_length=200)
    slug = models.SlugField()
    scientific_name = models.CharField(max_length=200)
    code = models.IntegerField(choices=ABA_CODES, default=0)
    apclass = models.ForeignKey(APClass, on_delete=models.CASCADE)
    body_html = models.TextField(null=True, blank=True)
    body_markdown = models.TextField(null=True, blank=True)
    # image = models.FileField(upload_to=get_upload_path, null=True, blank=True, help_text="width of high res is 1360px")
    # image_credit = models.CharField(max_length=200, blank=True, null=True)

    class Meta:
        verbose_name_plural = 'Animal/Plant'
        verbose_name = 'Animal/Plant'
        ordering = ["common_name", ]

    def __str__(self):
        return self.common_name

    def get_image_url(self):
        return "%s%s" % (settings.IMAGES_URL, self.image.url.split("media")[1][8:])

    def get_absolute_url(self):
        return reverse("sightings:detail", kwargs={"slug": self.slug})

    def kind(self):
        return self.apclass.kind

    def get_prev(self):
        model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name)
        return prev_in_order(self, model.objects.all())

    def get_next(self):
        model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name)
        return next_in_order(self, model.objects.all())

    @property
    def get_previous_admin_url(self):
        model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name)
        try:
            return reverse('admin:%s_%s_change' % (self._meta.app_label,  self._meta.model_name),  args=[self.get_prev().pk])
        except model.DoesNotExist:
            return ''

    @property
    def get_next_admin_url(self):
        model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name)
        try:
            return reverse('admin:%s_%s_change' % (self._meta.app_label,  self._meta.model_name),  args=[self.get_next().pk])
        except model.DoesNotExist:
            return ''

    def save(self, *args, **kwargs):
        if self.pk:
            md = render_images(self.body_markdown)
            self.body_html = markdown_to_html(md)
        self.slug = slugify(self.common_name[:50])
        super(AP, self).save(*args, **kwargs)


class Sighting(models.Model):
    ap = models.ForeignKey(AP, on_delete=models.CASCADE)
    point = models.PointField(blank=True)
    location = models.ForeignKey(Location, on_delete=models.CASCADE, blank=True)
    pub_date = models.DateTimeField('Date', default=timezone.now)
    # seen_by = models.ManyToManyField(User)
    # images = models.ManyToManyField(LuxImage, blank=True)
    # audio = models.ManyToManyField(BirdAudio, blank=True)

    class Meta:
        ordering = ["-pub_date", ]
        get_latest_by = "pub_date"

    @property
    def state(self):
        return self.location.state

    @property
    def country(self):
        return self.location.state.country

    @property
    def region(self):
        return self.location.state.country.lux_region

    @property
    def longitude(self):
        '''Get the site's longitude.'''
        return self.point.x

    @property
    def latitude(self):
        '''Get the site's latitude.'''
        return self.point.y

    @property
    def get_previous_admin_url(self):
        n = self.get_previous_by_pub_date()
        return reverse('admin:%s_%s_change' % (self._meta.app_label,  self._meta.model_name),  args=[n.id])

    @property
    def get_next_admin_url(self):
        model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name)
        try:
            return reverse('admin:%s_%s_change' % (self._meta.app_label,  self._meta.model_name),  args=[self.get_next_by_pub_date().pk])
        except model.DoesNotExist:
            return ''

    def get_small_image(self):
        for img in self.images.all():
            for size in img.sizes.all():
                if size.width > 360 and size.width < 700:
                    return img.get_image_by_size(size)

    def get_absolute_url(self):
        return reverse("sightings:detail", kwargs={"slug": self.ap.slug})

    def __str__(self):
        return self.ap.common_name

    def save(self, *args, **kwargs):
        if not self.point:
            self.point = Sighting.objects.latest().point
        try:
            self.location = Location.objects.filter(
                geometry__contains=self.point
            ).get()
        except Location.DoesNotExist:
            raise forms.ValidationError("There is no location associated with that point, add it:  %sadmin/locations/location/add/" % (settings.BASE_URL))
        super(Sighting, self).save()


"""
Migration from Birds to abstract:
apclass = OLDAPClass.objects.all()
for b in apclass:
    NewAPClass.objects.create(
        common_name = b.common_name,
        scientific_name = b.scientific_name,
        kind = 1
    )
 
ap = OLDAP.objects.all()
for b in ap:
    apnew = NewAPClass.objects.get(scientific_name=b.apclass.scientific_name)
    print(ap)
    NewAP.objects.create(
        common_name = b.common_name,
        scientific_name = b.scientific_name,
        code = b.code,
        apclass = apnew,
        image = b.image,
        image_credit = b.image_credit,
    )
    print(t)

oldsighting = OLDSighting.objects.all()
for bird in oldsighting:
    ap = NEWAP.objects.get(scientific_name=bird.ap.scientific_name)
    s = NEWSighting.objects.create(
        ap = ap,
        point = bird.point,
        location = bird.location,
        date = bird.date,
    )
    for t in bird.images.all():
        s.images.add(t)
    for t in bird.seen_by.all():
        s.seen_by.add(t)
"""