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 bs4 import BeautifulSoup

from locations.models import Location
from media.models import LuxImage, LuxImageSize

from utils.next_prev import next_in_order, prev_in_order
from utils.util import render_images, extract_main_image, markdown_to_html

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.ForeignKey(LuxImage, on_delete=models.CASCADE, 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.image.url.split("media")[1][8:])

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

    @property
    def seen(self):
        if self.sighting_set.all():
            return True
        else:
            return False

    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)
            main_image = extract_main_image(self.body_markdown)
            if main_image:
                self.image = main_image
                s = LuxImageSize.objects.get(name="featured_jrnl")
                self.image.sizes.add(s)
                self.image.save()
        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)
    location_name = models.CharField(max_length=200, blank=True)
    state_name = models.CharField(max_length=200, blank=True)
    country_name = models.CharField(max_length=200, blank=True)
    country_slug = models.CharField(max_length=200, blank=True)
    region_name = models.CharField(max_length=200, blank=True)
    ap_common_name = models.CharField(max_length=200, blank=True)
    # 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_url_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.MultipleObjectsReturned:
            for l in Location.objects.filter(geometry__contains=self.point):
                print(l)
                print(l.parent)
                if l.parent:
                    self.location = l
                    break
        except Location.DoesNotExist:
            raise forms.ValidationError("There is no location associated with that point, add it:  %sadmin/locations/location/add/" % (settings.BASE_URL))
        self.ap_common_name = self.ap.common_name
        self.location_name = self.location.name
        self.state_name = self.location.state.name
        self.country_name = self.location.state.country.name
        self.country_slug = self.location.state.country.slug
        self.region_name = self.location.state.country.lux_region.name
        super(Sighting, self).save()


class FieldNote(models.Model):
    sighting = models.ForeignKey(Sighting, on_delete=models.CASCADE)
    body_html = models.TextField(blank=True)
    body_markdown = models.TextField(blank=True)
    # these are only used to speed up admin
    sighting_pub_date = models.DateTimeField('Date', blank=True)
    sighting_location = models.CharField(max_length=200, blank=True)
    ap_common_name = models.CharField(max_length=200, blank=True)

    class Meta:
        ordering = ["sighting_pub_date", ]

    def __str__(self):
        return '%s %s' % (self.ap_common_name, self.pk)

    def save(self, *args, **kwargs):
        self.sighting_pub_date = self.sighting.pub_date
        self.ap_common_name = self.sighting.ap.common_name
        self.sighting_location = self.sighting.location_name
        md = render_images(self.body_markdown)
        self.body_html = markdown_to_html(md)
        super(FieldNote, self).save()