import datetime
import json
import operator
import os
import re
from functools import reduce
from pathlib import Path
from urllib.parse import urljoin

from django.conf import settings
from django.db import models
from django.urls import reverse

from troggle.core.models.wallets import Wallet
# from troggle.core.models.troggle import DataIssue # circular import. Hmm

class SurvexDirectory(models.Model):
    path = models.CharField(max_length=200)
    cave = models.ForeignKey('Cave', blank=True, null=True,on_delete=models.SET_NULL)
    primarysurvexfile = models.ForeignKey('SurvexFile', related_name='primarysurvexfile', blank=True, null=True,on_delete=models.SET_NULL)
    # could also include files in directory but not referenced
    
    class Meta:
        ordering = ('id',)
        verbose_name_plural = "Survex directories"

    def __str__(self):
        return "[SurvexDirectory:"+str(self.path)  + " |  Primary svx:" + str(self.primarysurvexfile.path) +".svx ]" 


class SurvexFile(models.Model):
    path = models.CharField(max_length=200)
    survexdirectory = models.ForeignKey("SurvexDirectory", blank=True, null=True,on_delete=models.SET_NULL)
    cave = models.ForeignKey('Cave', blank=True, null=True,on_delete=models.SET_NULL)
    
    class Meta:
        ordering = ('id',)

    # Don't change from the default as that breaks troggle webpages and internal referencing!
    # def __str__(self):
        # return "[SurvexFile:"+str(self.path) + "-" + str(self.survexdirectory) + "-" + str(self.cave)+"]" 

    def exists(self):
        fname = os.path.join(settings.SURVEX_DATA, self.path + ".svx")
        return os.path.isfile(fname)
    
    def OpenFile(self):
        fname = os.path.join(settings.SURVEX_DATA, self.path + ".svx")
        return open(fname)
    
    def SetDirectory(self):
        dirpath = os.path.split(self.path)[0]
        # pointless search every time we import a survex file if we know there are no duplicates..
        # don't use this for initial import.
        survexdirectorylist = SurvexDirectory.objects.filter(cave=self.cave, path=dirpath)
        if survexdirectorylist:
            self.survexdirectory = survexdirectorylist[0]
        else:
            survexdirectory = SurvexDirectory(path=dirpath, cave=self.cave, primarysurvexfile=self)
            survexdirectory.save()
            self.survexdirectory = survexdirectory
        self.save()
        
    def __str__(self):
        return self.path

class SurvexStationLookUpManager(models.Manager):
    def lookup(self, name):
        blocknames, sep, stationname = name.rpartition(".")
        return self.get(block = SurvexBlock.objects.lookup(blocknames),
                        name__iexact = stationname)

class SurvexStation(models.Model):
    name        = models.CharField(max_length=100)   
    block       = models.ForeignKey('SurvexBlock', null=True,on_delete=models.SET_NULL)
    objects = SurvexStationLookUpManager()
    x = models.FloatField(blank=True, null=True)
    y = models.FloatField(blank=True, null=True)
    z = models.FloatField(blank=True, null=True)
    
    def path(self):
        r = self.name
        b = self.block
        while True:
            if b.name:
                r = b.name + "." + r
            if b.parent:
                b = b.parent
            else:
                return r

    class Meta:
        ordering = ('id',)
    def __str__(self):
        return self.name and str(self.name) or 'no name'

#
# Single SurvexBlock 
# 
class SurvexBlockLookUpManager(models.Manager):
    """Don't know what this does, suspect it is part of the Django admin
    system"""
    def lookup(self, name):
        if name == "":
            blocknames = []
        else:
            blocknames = name.split(".")
        block = SurvexBlock.objects.get(parent=None, survexfile__path=settings.SURVEX_TOPNAME)
        for blockname in blocknames:
            block = SurvexBlock.objects.get(parent=block, name__iexact=blockname)
        return block

class SurvexBlock(models.Model):
    """One begin..end block within a survex file. The basic element of a survey trip.
    """
    objects = SurvexBlockLookUpManager()
    name       = models.CharField(max_length=100)
    title      = models.CharField(max_length=200)
    parent     = models.ForeignKey('SurvexBlock', blank=True, null=True,on_delete=models.SET_NULL)
    cave       = models.ForeignKey('Cave', blank=True, null=True,on_delete=models.SET_NULL)
    
    date       = models.DateField(blank=True, null=True)
    expedition = models.ForeignKey('Expedition', blank=True, null=True,on_delete=models.SET_NULL)
        
    survexfile = models.ForeignKey("SurvexFile", blank=True, null=True,on_delete=models.SET_NULL)
    survexpath = models.CharField(max_length=200)   # the path for the survex stations
    
    scanswallet = models.ForeignKey("Wallet", null=True,on_delete=models.SET_NULL)  # only ONE wallet per block. The most recent seen overwites.. ugh.
    
    legsall   = models.IntegerField(null=True)  # summary data for this block
    legslength = models.FloatField(null=True)
    
    class Meta:
        ordering = ('id',)

    def __str__(self):
        return "[SurvexBlock:"+ str(self.name) + "-path:" + \
            str(self.survexpath) + "-cave:" + \
            str(self.cave) + "]" 
            
    def __str__(self):
        return self.name and str(self.name) or 'no name'

    def isSurvexBlock(self): # Function used in templates
        return True

    def DayIndex(self):
        """This is used to set different colours for the different trips on
        the calendar view of the expedition"""
        mx = 10
        index = list(SurvexBlock.objects.filter(date=self.date)).index(self)
        if index not in range(0, mx):
            print(f"DayIndex: More than {mx-1} SurvexBlock items on one day '{index}' {self}")
            index = 0
        #return list(self.survexblock_set.all()).index(self)
        return index

class SurvexPersonRole(models.Model):
    survexblock         = models.ForeignKey('SurvexBlock',on_delete=models.CASCADE)
        # increasing levels of precision, Surely we only need survexblock and person now that we have no link to a logbook entry?
    personname          = models.CharField(max_length=100)
    person              = models.ForeignKey('Person', blank=True, null=True,on_delete=models.SET_NULL)
    personexpedition    = models.ForeignKey('PersonExpedition', blank=True, null=True,on_delete=models.SET_NULL)
    # expeditionday       = models.ForeignKey("ExpeditionDay", null=True,on_delete=models.SET_NULL)
    
    def __str__(self):
        return str(self.personname) + " - " + str(self.survexblock) 

class SingleScan(models.Model):
    """A single file holding an image. Could be raw notes, an elevation plot or whatever
    """
    ffile    = models.CharField(max_length=200)
    name     = models.CharField(max_length=200)
    wallet   = models.ForeignKey("Wallet", null=True,on_delete=models.SET_NULL)
    
    class Meta:
        ordering = ('name',)
    
    def get_absolute_url(self):
        return urljoin(settings.URL_ROOT, reverse('scansingle', kwargs={"path":re.sub("#", "%23", self.wallet.walletname), "file":self.name}))
 
    def __str__(self):
        return "Scan Image: " + str(self.name) + " in " + str(self.wallet)

class DrawingFile(models.Model):
    """A file holding a Therion (several types) or a Tunnel drawing
    """
    dwgpath          = models.CharField(max_length=200)
    dwgname          = models.CharField(max_length=200)
    dwgwallets       = models.ManyToManyField("Wallet") # implicitly links via folders to scans to SVX files
    scans            = models.ManyToManyField("SingleScan")  # implicitly links via scans to SVX files
    dwgcontains      = models.ManyToManyField("DrawingFile")  # case when its a frame type
    filesize         = models.IntegerField(default=0)
    npaths           = models.IntegerField(default=0)
    survexfiles      = models.ManyToManyField("SurvexFile")  # direct link to SVX files - not populated yet

    class Meta:
        ordering = ('dwgpath',)

    def __str__(self):
        return "Drawing File: " + str(self.dwgname) + " (" + str(self.filesize) + " bytes)"