import os, stat
import re
import datetime
from pathlib import Path
from urllib.parse import urljoin, unquote as urlunquote
from urllib.request import urlopen

from django.conf import settings
from django.shortcuts import render
from django.http import HttpResponse

from troggle.core.models.survex import Wallet, SingleScan, SurvexBlock
from troggle.core.models.troggle import Person, Expedition
from troggle.core.models.troggle import DataIssue
from troggle.core.models.caves import GetCaveLookup
from troggle.core.views.expo import getmimetype
#from troggle.parsers.people import GetPersonExpeditionNameLookup

#import parsers.surveys

'''one of these views serves files as binary blobs, and simply set the mime type based on the file extension,
as does the urls.py dispatcher which sends them here. Here they should actually have the filetype checked 
by looking inside the file before being served.

need to check if inavlid query string is invalid, or produces multiple replies
and render a user-friendly error page.

Note that datewallet(), caveifywallet() etc do NOT save the object to the db. They are ephemeral, just for the page rendering of the
manywallets dict.

TODO 
cave for a wallet - just gets the last one, randomly. SHould make this a list or many:many ideally

add this file in to the todo list thinggy.
'''

def populatewallet(w):
    '''Copy survex data here just for display, not permanently
    
    Only gets data from the survex file when it was parsed on import..
    so doesn't work if there is no *ref value
    '''
    survexpeople = []
    blocks = SurvexBlock.objects.filter(scanswallet = w)
    for b in blocks:
        for personrole in b.survexpersonrole_set.all(): 
            survexpeople.append(personrole.personname)
        w.persons = list(set(survexpeople)) 

def datewallet(w, earliest):
    first = earliest
    blocks = SurvexBlock.objects.filter(scanswallet = w)
    for b in blocks:
        if b.date:
            if b.date < first:
                first = b.date    
    if first == earliest:
        # no date found
        w.date = None
    else:
        w.date = first.isoformat()
    
def caveifywallet(w):
    '''Gets the cave from the list of survex files,
    only selects one of them though. Only used for display.
    '''
    #print(f' - Caveify {w=}')
    blocknames = []
    blocks = SurvexBlock.objects.filter(scanswallet = w)
    for b in blocks:    
        # NB b.cave is not populated by parser. Use b.survexfile.cave instead, or we could parse b.survexpath
        if b.survexfile.cave:
            w.caveobj  = b.survexfile.cave # just gets the last one, randomly. SHould make this a list or many:many ideally
            w.cave = w.caveobj
        if b.name:
            blocknames.append(b.name)
 
    if w.name():
        w.displaynames = [w.name()]
    else:
        w.displaynames = blocknames
        
def fillblankpeople(w):
        # this isn't working..? why? Because it needs a *ref and an import
        wp = w.people()
        w.persons = wp
        if not wp:
            populatewallet(w)
        else:
            if len(wp) == 1:
                # print(f' - {wp=}')
                nobody = wp[0].lower()
                if  nobody == 'unknown' or nobody == 'nobody' or nobody == ' ' or nobody == '':
                    # print(f' - {wp=} {nobody=}')
                    populatewallet(w)
        
def fillblankothers(w):       
    earliest = datetime.datetime.now().date()
    if not w.date():
        datewallet(w, earliest)
        
    Gcavelookup = GetCaveLookup()

    wcaveid = w.cave()
    if not wcaveid or wcaveid == "":
        caveifywallet(w)
    else:
        if wcaveid in Gcavelookup:
            w.caveobj = Gcavelookup[wcaveid]
            # print(f' - Found cave object from id {wcaveid}')
        else:
            print(f' - Failed to find cave object from id {wcaveid}')

        
def fixsurvextick(w, ticks):   
    ticks["S"] = w.fixsurvextick(ticks["S"]) 

 
def walletslistperson(request, first_name, last_name):
    '''Page which displays a list of all the wallets for a specific person
    HORRIBLE linear search through everything. Index and do SQL query properly
    '''
    # This is where we face having to re-do everything to do with names properly, rather than the horrible series of hacks over 20 years..
    #GetPersonExpeditionNameLookup
    def tickspersonwallet(p):
        manywallets = []
        wallets = Wallet.objects.all()
        for w in wallets:
            w.persons = w.people() # ephemeral attribute for web page
            fillblankpeople(w)
            if w.persons:
                if p.fullname in w.persons:
                    manywallets.append(w)
                    fillblankothers(w)
                    w.ticks = w.get_ticks() # the complaints in colour form
                    fixsurvextick(w, w.ticks)
        return manywallets
    
    try:
        if last_name:
            p = Person.objects.get(fullname= f'{first_name} {last_name}')
        else: 
            # speciall Wookey-hack
            p = Person.objects.get(first_name= f'{first_name}')
    except:
        #raise
        return render(request, 'errors/generic.html', {'message': f'Unrecognised name of a expo person: "{first_name} {last_name}"'})   
    
    manywallets = tickspersonwallet(p)

    return render(request, 'personwallets.html', { 'manywallets':manywallets, 'settings': settings, 'person': p})


def walletslistyear(request, year):
    '''Page which displays a list of all the wallets in a specific year 
    '''
    def ticksyearwallet(year):
        manywallets = []
        wallets = Wallet.objects.all() 
        for w in wallets:

            if year == w.year():
                manywallets.append(w)
                fillblankpeople(w)
                fillblankothers(w)
                w.ticks = w.get_ticks() # the complaints in colour form, from the json file on disc
                fixsurvextick(w, w.ticks)
            else:
                continue

        return manywallets
        
    if year < 1976 or year > 2050:
        return render(request, 'errors/generic.html', {'message': 'Year out of range. Must be between 1976 and 2050'})   
    else:
        year = str(year)
    #return render(request, 'errors/generic.html', {'message': 'This page logic not implemented yet'})   

    manywallets = ticksyearwallet(year)
    expeditions = Expedition.objects.all()
    expedition = Expedition.objects.filter(year=year)
    return render(request, 'yearwallets.html', { 'manywallets':manywallets, 'settings': settings, 'year': year, 'expeditions': expeditions, 'expedition': expedition})



def cavewallets(request, caveid):
    '''Returns all the wallets for just one cave
    '''
    Gcavelookup = GetCaveLookup()
    if caveid in Gcavelookup:
        cave = Gcavelookup[caveid]
    else:
        return render(request,'errors/badslug.html', {'badslug': caveid})

    # remove duplication. Sorting is done in the template
    # But this only gets wallets which have survex files attached..
    wallets = set(Wallet.objects.filter(survexblock__survexfile__cave=cave))
    
    # all the ones without a survexblock attached via a *ref, search for match in JSON
    zilchwallets = set(Wallet.objects.exclude(survexblock__survexfile__cave=cave))
    for z in zilchwallets:
        zcaveid = z.cave()
        if zcaveid:
            if str(zcaveid) in Gcavelookup:
                fcave = Gcavelookup[str(zcaveid)]
                if str(fcave.slug()) == caveid:
                    # print(f' - Found one ! {z.walletname=} {zcaveid=}')
                    wallets.add(z)
            else:
                wurl = f"/scanupload/{z.walletname.replace('#',':')}"
                print(f' - Unrecognised cave name \'{zcaveid}\' in {z.walletname}  (out of {len(Gcavelookup):,} cave names and aliases)')
                message = f" ! In {z.walletname} there is an unrecognised cave name '{zcaveid}' (out of {len(Gcavelookup):,} cave names"
                DataIssue.objects.update_or_create(parser='scans', message=message, url=wurl)

    manywallets = list(set(wallets))
    for w in manywallets:
        fillblankpeople(w)
        fillblankothers(w)   
        w.ticks = w.get_ticks() # the complaints in colour form, from the json file on disc
        fixsurvextick(w, w.ticks)
    return render(request, 'cavewallets.html', { 'manywallets':manywallets, 'settings': settings, 'cave': cave})


def oldwallet(request, path):
    '''Now called only for non-standard wallet structures for pre-2000 wallets
    '''
    # print([ s.walletname  for s in Wallet.objects.all() ])
    print(f'! - oldwallet path:{path}')
    try:
        wallet = Wallet.objects.get(walletname=urlunquote(path))  
        return render(request, 'wallet_old.html', { 'wallet':wallet, 'settings': settings })
    except:
        message = f'Scan folder error or not found \'{path}\' .'
        return render(request, 'errors/generic.html', {'message': message})   


def scansingle(request, path, file):
    '''sends a single binary file to the user for display - browser decides how using mimetype
    '''
    try:
        wallet = Wallet.objects.get(walletname=urlunquote(path)) 
        singlescan = SingleScan.objects.get(wallet=wallet, name=file)
        print(" - scansingle {}:{}:{}:".format(path, file, getmimetype(file)))
        return HttpResponse(content=open(singlescan.ffile,"rb"), content_type=getmimetype(file)) # any type of image
    except:
        message = f'Scan folder or scan item error or not found \'{path}\'  and \'{file}\'.'
        return render(request, 'errors/generic.html', {'message': message})   


def allscans(request):
    '''Returns all the wallets in the system, we would like to use
    the Django queryset SQL optimisation https://docs.djangoproject.com/en/3.2/ref/models/querysets/#prefetch-related
    to get the related singlescan and survexblock objects but that requires rewriting this to do the query on those, not on
    the wallets
    '''
    manywallets = Wallet.objects.all() # NB all of them
    # manywallets = Wallet.objects.all().prefetch_related('singlescan') fails as the link is defined on 'singlescan' not on 'wallet'
    return render(request, 'manywallets.html', { 'manywallets':manywallets, 'settings': settings })