import json
import gzip
import pytz
from datetime import datetime

from django.shortcuts import render
from django.http import JsonResponse, HttpResponse
from django.conf import settings
from django.core.serializers.json import DjangoJSONEncoder
from django.views import View
from django.core.cache import cache
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.gis.geos import Point
from django.db.models import Q

from .models import *
from .workers.points2trips import TripConverter

def index(request):
  return render(request, 'gps_logger/index.html')

def secrets(request):
  secrets = {
    'cesium_token': settings.CESIUM_TOKEN,
    'bing_maps_key': settings.BING_MAPS_KEY
  }
  return JsonResponse(secrets)

@permission_required("gps-logger.markers.change")
def upload(request):
  return render(request, 'gps_logger/upload.html')

class MarkerCreateView(PermissionRequiredMixin, View):
  permission_required = ("gps-logger.markers.change")

  def post(self, request):
    utctz = pytz.timezone("UTC")
    insert_count = censor_count = replace_count = 0
    data = json.loads(request.body)
    minDate = datetime.utcnow().replace(tzinfo=utctz)
    for file in data:
      if len(data[file]) == 0:
        continue
      objects = [Marker(
          timestamp=datetime.strptime(x['timestamp'].replace("Z","-0000"), r"%Y-%m-%dT%H:%M:%S.%f%z"),
          location = Point(x['lng'], x['lat'], srid=4326),
          alt = x['alt'],
          hdop = x.get('hdop', None),
          speed = x.get('speed', None)
        ) for x in data[file]]
      start_date = objects[0].timestamp
      end_date = objects[-1].timestamp
      oldMarkers = Marker.objects.filter(timestamp__range=(start_date, end_date)).all()
      identical = oldMarkers.count() == len(objects)

      minDate = min(minDate, start_date)

      if identical:
        for i, marker in enumerate(oldMarkers):
          if marker.timestamp != objects[i].timestamp:
            identical = False
            break

      if identical:
        for i, marker in enumerate(oldMarkers):
          objects[i].id = marker.id
        Marker.objects.bulk_update(objects, ['location', 'alt', 'hdop', 'speed'])
        replace_count += oldMarkers.count()
      else:
        insert_count += len(objects) - oldMarkers.count()
        oldMarkers.delete()
        Marker.objects.bulk_create(objects)
    
    censor_count = censor()

    minDate = minDate.replace(hour=0, minute=0, second=0, microsecond=0)
    print("regenerating trips after", minDate)
    tc = TripConverter(minDate)
    tc.run()
    cache.delete('trips')

    return JsonResponse({
        'markers_censored': censor_count,
        'markers_replaced': replace_count,
        'markers_inserted': insert_count - censor_count,
        'trips_created': tc.created,
        'trips_updated': tc.updated,
        'trips_skipped': tc.skipped
      }, status=201)

class CreateTripsView(PermissionRequiredMixin, View):
  permission_required = ("gps-logger.trips.change")

  def get(self, request):
    tc = TripConverter()
    tc.run()
    cache.delete('trips')
    return JsonResponse({
        'created': tc.created,
        'updated': tc.updated,
        'skipped': tc.skipped
      }, status=201)


def marker_view(request):
  data = cache.get('markers')
  if not data:
    values = list(Marker.objects.values())
    for marker in values:
      location  = marker['location']
      if location:
        marker['lng'] = location.x
        marker['lat'] = location.y
      del marker['location']
    data = json.dumps(values, cls=DjangoJSONEncoder)
    cache.set('markers', data, 3600*24*30)
  return HttpResponse(data, content_type='application/json')

def trip_view(request):
  data = cache.get('trips')
  if not data:
    values = list(Trip.objects.values())
    for trip in values:
      trip['path'] = json.loads(gzip.decompress(trip['path']))
      trip['startTime'] = trip['startTime'].timestamp()
      trip['endTime'] = trip['endTime'].timestamp()
      trip['movementTime'] = trip['movementTime'].total_seconds()
      trip['totalTime'] = trip['totalTime'].total_seconds()
      trip['center'] = {
        'lng': trip['center'].x,
        'lat': trip['center'].y
      }
      trip['minLng'], trip['minLat'], trip['maxLng'], trip['maxLat'] = trip['line'].extent
      del trip['line']
    data = json.dumps(values)
    cache.set('trips', data, 3600*24*30)
  return HttpResponse(data, content_type='application/json')

class DeleteCensoredView(PermissionRequiredMixin, View):
  permission_required = ("gps-logger.markers.change",)
  def get(self, request):
    counter = censor()
    return JsonResponse({'censored': counter})

def censor() -> int:
  locations = CensoredLocation.objects.all()
  filter = None
  for location in locations:
    f = Q(location__distance_lte=(location.location, distance_to_decimal_degrees(D(m=location.radius), location.location.y)))
    filter = f if filter is None else filter | f

  matches = Marker.objects.filter(filter)
  counter, _ = matches.delete()

  cache.delete('markers')
  return counter