from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.contrib.auth.views import PasswordResetView, PasswordResetConfirmView  # class-based views

from django.urls import include, path, re_path

from troggle.core.views import statistics, survex
from troggle.core.views.auth import expologin, expologout
from troggle.core.views.caves import (
    cave3d,
    cave_debug,
    caveindex,
    cavepage,
    caveQMs,
    caveslist,
    caveslugfwd,
    edit_cave,
    edit_entrance,
    entranceindex,
    entrancetags,
    expo_kml,
    expo_kmz,
    get_entrances,
    qm,
)
from troggle.core.views.cave_kataster import kataster, fix
from troggle.core.views.drawings import dwgallfiles, dwgfilesingle
from troggle.core.views.editor_helpers import image_selector, new_image_form
from troggle.core.views.expo import (
    editexpopage,
    expofiles_redirect,
    expofilessingle,
    expopage,
    indexpage,
    map,
    mapfile,
    mediapage,
    pubspage,
    spider,
)
from troggle.core.views.logbook_edit import logbookedit
from troggle.core.views.logbooks import (
    Expeditions_jsonListView,
    Expeditions_tsvListView,
    QMs_jsonListView,
    expedition,
    get_logbook_entries,
    get_people,
    logbookentry,
    logentrydelete,
    logreport,
    notablepersons,
    people_ids,
    person,
    personexpedition,
)
from troggle.core.views.other import controlpanel, exportlogbook, frontpage, todos, public_laptop, folk_export
from troggle.core.views.prospect import prospecting
from troggle.core.views.user_registration import register, newregister, reset_done, ExpoPasswordResetForm
from troggle.core.views.scans import allscans, cavewallets, scansingle, walletslistperson, walletslistyear
from troggle.core.views.signup import signup, signupok
from troggle.core.views.uploads import dwgupload, expofilerename, gpxupload, photoupload
from troggle.core.views.wallets_edit import walletedit

# from troggle.core.views.user_registration import SignUpView # Warning: a Class-based View

"""This sets the actualurlpatterns[] and urlpatterns[] lists which django uses 
to resolve urls - in both directions as these are declarative. 

HOW THIS WORKS
This is a "url dispatcher" - something needed by every web framework.
re_path( <regular expression that matches the thing in the web browser>,
<reference to python function in 'core' folder>, <optional name>)

Django also provides the reverse function: given an an object, provide the URL
which is important to writing code for the webapp. So the URL dispatch is declarative.
But this means that two URLs should NOT go to the same python target function,
(or only if the target name is different)

The API urls return TSV or JSON and are new in July 2020.

CONVENTION
Unlike most DJango projects, we have the convention that we do NOT have a terminal slash
on the URL of a page which is generated. (Generated pages are neither files not directories.)
So the url is "/dwgfiles" not "/dwgfiles/" everywhere, and similarly for "/walletedit" etc.
This is important in troggle because we do NOT universally use the reverse() function 
or the url() function to get the URL from the declarations in this url.py file.
The reason is that url() requires quite a wide knowledge of troggle, whereas explicit
urls can be done by beginner maintainers and work (but do add to future maintenance).

NOTE
- The admin and logout paths need to stay using re_path() as they 
  have to be locked to the start.
  
- admin and login forms are provided by Django so we have to fit in to their conventions.

- The final _edit and CATCHALL also have to use re_path().

(?P<thing>)
This strange syntax is not a Django funny, it is standard (but obscure) python.
It denotes a "Named Capturing Group" 
https://docs.python.org/3/howto/regex.html#non-capturing-and-named-groups
https://dnmtechs.com/understanding-the-django-regular-expression-p-in-python-3/
https://www.regular-expressions.info/named.html
e.g. the regular expression:
r'^(?P<path>.*)/(?P<slug>[^/]+)_cave_edit/$'

Many of these patterns do not work because troggle spent many years broken and we have
not yet restored all the functions. Some may have never been fully implemented in
the first place and what they were intended to provide is obscure.

Some short names such as indxal.htm date from the Archimedes-era when filenames had to be less
than 10-chars long.
"""

todo = '''
- Replace more re_path() with modern and simpler path(). Careful: some have to stay as re_path()

- Test VERY CAREFULLY for each change. It is fragile.
'''



# WHen running on the server, apache intercepts all the /expofiles/ files so troggle never sees them,
# so the "content type" is set by whatever apache thinks it should be. Which means .gpx files
# get treated as XML and the web browser fails to do anything useful

if settings.EXPOFILESREMOTE:
    expofilesurls = [
        path('<path:filepath>',    expofiles_redirect, name="expofiles_redirect"), # to http://expo.survex.com/expofiles
        path('',                 expofiles_redirect, {'filepath': ""}, name="expofiles_redirect"), #should not have duplicate urls as reverse() then fails
        ]
else:
    expofilesurls = [
        path('',              expofilessingle, {'filepath': ""}, name="single"), 
        path('<path:filepath>', expofilessingle, name="single"), # local copy of EXPOFILES, but should not have duplicate urls as reverse() then fails
        ]


trogglepatterns = [
    # NOT intercepted by apache. Needs to come first to prevent our troggle middleware trying to "fix" it.
    re_path(r'^site_media/(?P<subpath>.*)$',  mediapage, {'doc_root': settings.MEDIA_ROOT},  name="mediapage"), # MEDIA_ROOT: CSS and JS

    path('pubs.htm', pubspage,      name="pubspage"), # ~165 hrefs to this url in expoweb files
    #path('', indexpage,      name="indexpage"), # ~1,212 hrefs to this url in expoweb files
    path('index.htm', indexpage,      name="indexpage"), # ~1,212 hrefs to this url in expoweb files

    path('expofiles/', include(expofilesurls)), # intercepted by Apache, if it is running.
    path('expofiles',  include(expofilesurls)), # curious interaction with the include() here, not just a slash problem.

    re_path(r'^(.*)_edit_edit$',    spider, name="spider"), # web spider. Intercept and manage it.

    re_path(r'^caves$',      caveindex,      name="caveindex"),
    re_path(r'^indxal.htm$', caveindex,      name="caveindex"), # ~420 hrefs to this url in expoweb files
    re_path(r'^people/?$',   notablepersons, name="notablepersons"),
    path('people_ids',   people_ids, name="people_ids"),
    path('folk_export',   folk_export, name="folk_export"),
    path('caveslist',        caveslist,      name="caveslist"),

    path('entrances',      entranceindex,      name="entranceindex"),
    path('enttags',      entrancetags,      name="entrancetags"),

    re_path(r'^admin/doc/',  include('django.contrib.admindocs.urls')), # needs docutils Python module (http://docutils.sf.net/).
    path('admin/',      admin.site.urls), # includes admin login & logout urls  & /admin/jsi18n/ NOTE TERMINAL SLASH
    
# Uploads - uploading a file
    path('walletedit',                  walletedit,  name='walletedit'), # not just an upload, also edit metadata
    path('walletedit/<path:path>',        walletedit,  name='walletedit'), # path=2020#01
    path('photoupload',                 photoupload, name='photoupload'), # restricted to current year
    path('photoupload/<path:folder>',      photoupload, name='photoupload'), # restricted to current year
    path('gpxupload',                   gpxupload, name='gpxupload'), # restricted to current year
    path('gpxupload/<path:folder>',       gpxupload, name='gpxupload'), # restricted to current year
    path('dwgupload/<path:folder>',       dwgupload,   name='dwgupload'), 
    path('dwgupload',                   dwgupload,   name='dwgupload'), 
    path('dwguploadnogit',              dwgupload,  {'gitdisable': 'yes'}, name='dwguploadnogit'), # used in testing
    path('dwguploadnogit/<path:folder>', dwgupload,  {'gitdisable': 'yes'}, name='dwguploadnogit'), # used in testing
    path('logbookedit/',                 logbookedit,  name='logbookedit'), 
    path('logbookedit/<slug:slug>',      logbookedit,  name='logbookedit'), 
    path('signup',                       signup,  name='signup'), 
    path('signupok',                     signupok,  name='signupok'), 

# Renaming an uploaded file
    path('expofilerename/<path:filepath>', expofilerename,  name='expofilerename'), 

# see https://docs.djangoproject.com/en/dev/topics/auth/default/tiny
# The URLs provided by include('django.contrib.auth.urls') are:
# 
# accounts/login/ [name='login']
# accounts/logout/ [name='logout']
# accounts/password_change/ [name='password_change']
# accounts/password_change/done/ [name='password_change_done']
# accounts/password_reset/ [name='password_reset']
# accounts/password_reset/done/ [name='password_reset_done']
# accounts/reset/<uidb64>/<token>/ [name='password_reset_confirm']
# accounts/reset/done/ [name='password_reset_complete']

# BUT many of these are set up by opinionated Django even if 'django.contrib.auth.urls' is NOT included.
# Some overlap with 'admin.site.urls' needs to be investigated.

# admin.site.urls is urls() which maps to get_urls() which is a function declared  
# in django/contrib/admin/sites.py which for me is 
# /home/philip/expo/troggle/.venv/lib/python3.xx/site-packages/django/contrib/admin/sites.py

# setting LOGIN_URL = '/accounts/login/' is default. 
#   NB setting url pattern name to 'login' instead of 'expologin' with override Django, see https://docs.djangoproject.com/en/dev/topics/http/urls/#naming-url-patterns
    path('accounts/logout/',   expologout, name='expologout'), # same as in django.contrib.auth.urls
    path('accounts/login/',    expologin,  name='expologin'),  # same as in django.contrib.auth.urls
    path("accounts/register/<slug:url_username>", register, name="re_register"),    # overriding django.contrib.auth.urls
    path("accounts/register/", register,                name="register"),           # overriding django.contrib.auth.urls
    path("accounts/newregister/", newregister,          name="newregister"),        
    path("accounts/reset/done/", reset_done,   name="password_reset_done"), # overriding django.contrib.auth.urls
    path('accounts/password_reset/', PasswordResetView.as_view(form_class=ExpoPasswordResetForm), name='password_reset'),
    path('accounts/reset/<uidb64>/<token>/', PasswordResetConfirmView.as_view(), name="password_reset_confirm"),
    path('accounts/', include('django.contrib.auth.urls')),  # see line 109 in this file NB initial "/accounts/" in URL
    
    path('expo_laptop', public_laptop, name="public_laptop"),

    path('person/<slug:slug>', person, name="person"),
    path('personexpedition/<slug:slug>/<int:year>', personexpedition, name="personexpedition"),

#   Expedition master page & API exports
    re_path(r'^expedition/(\d+)$',  expedition,  name="expedition"),
    re_path(r'^api/expeditions_tsv$', Expeditions_tsvListView.as_view()),
    re_path(r'^api/expeditions_json$', Expeditions_jsonListView.as_view()),
    re_path(r'^api/QMs_json$', QMs_jsonListView.as_view()),

#   Logbook entries
    re_path(r'^logbookentry/(?P<date>.*)/(?P<slug>.*)/?$', logbookentry,name="logbookentry"),   
    re_path(r'^logbook$', exportlogbook, name='exportlogbook'), 
    path('logreport/<slug:year>', logreport, name='logreport'), 
    path('logentrydelete/<slug:year>', logentrydelete, name='logentrydelete'), 
   
#   Internal. editfile.html template uses these internally
    re_path(r'^getPeople/(?P<expeditionslug>.*)', get_people, name = "get_people"), 
    re_path(r'^getLogBookEntries/(?P<expeditionslug>.*)', get_logbook_entries, name = "get_logbook_entries"), 
    re_path(r'^getEntrances/(?P<caveslug>.*)', get_entrances, name = "get_entrances"), 

#   Cave description pages
    path('cave/<slug:slug>',  caveslugfwd,  name="caveslugfwd"), 
    path('cave_debug',  cave_debug,  name="cave_debug"), 
    path('kataster/<slug:slug>',  kataster,  name="kataster"), # for renaming a cave from e.g. 1623-2005-05 to 1623-264
    path('kataster',  kataster,  name="kataster"), # illustrative placeholder for kataster renaming
    path('fix/<slug:areacode>',  fix,  name="fix"), # one-off fix misplaced images and descriptive files
    re_path(r'^newcave/$', edit_cave, name="newcave"),
    re_path(r'^cave/3d/(?P<cave_id>[^/]+).3d$', cave3d, name="cave3d"),
    
#   Edit caves and entrances
    re_path(r'^(?P<path>.*)/(?P<slug>[^/]+)_cave_edit/$',           edit_cave, name="edit_cave"), # edit_cave needed by cave.html template for url matching
    re_path(r'^(?P<caveslug>[^/]+):(?P<entslug>[^:]+)_entrance_edit', edit_entrance, name = "editentrance"), #edit existing entrance
    re_path(r'^(?P<path>.*)/(?P<caveslug>[^/]+)_entrance_new$', edit_entrance, name = "newentrance"), # new entrance for a cave

    re_path(r'^(.*)_edit$',         editexpopage, name="editexpopage"), # only happens if not a cave or entrance _edit page
    re_path(r'^(?P<karea>162\d)(?P<subpath>.*)$',   cavepage,  name="cavepage"), # shorthand /1623/264 or 1623/161/top.htm or 1623/161/i/stuff.jpg
    # Note that urls eg '/1623/161/l/rl89a.htm' are handled by cavepage which redirects them to 'expopage'    
    # Note that _edit$ for a cave description page in a subfolder e.g. /1623/204/204.html_edit  gets caught here and breaks with 404
    
    # These re-enable archaic URLs which are in old web pages which may still be public on other servers - old
    # path('smkridge/<path:subpath>',  cavepagefwd,  {'karea': "1623"}, name="cavepagefwd"), 
    # path('expo/smkridge/<path:subpath>',  cavepagefwd,  {'karea': "1623"}, name="cavepagefwd"), 

    # Archaic, kept. This /expo/ prefix only works for expoweb HTML pages not troggle pages   
    path('expo/<path:path>',              expopage,     name="expopage"),  
       
# System admin and monitoring
    path('statistics',        statistics.stats,       name="stats"),
    path('stats',             statistics.stats,       name="stats"),
    path('pathsreport',       statistics.pathsreport, name="pathsreport"),
    path('dataissues',        statistics.dataissues,  name="dataissues"),
    path('therionissues',     statistics.therionissues,  name="therionissues"),
    path('surveximport',      statistics.surveximport,  name="surveximport"),
    path('survexdebug',       statistics.survexdebug, name="survexdebug"),
    path('stations',          statistics.stations,    name="stations"),
    path('aliases/<int:year>',statistics.aliases,     name="aliases"),

    path('troggle',            frontpage,     name="frontpage"), # control panel. Shows recent actions.
    path('todo/<path:module>', todos,         name="todos"),
    path('controlpanel',       controlpanel,  name="controlpanel"),

# The survexfile pages
    path('survexdir',                     survex.survexdir,  name="survexdir"),
    
    path('survexfile',                    survex.survexcavesingle, {'cave_shortname': ''},   name="survexcavessingle"),
    path('survexfile/caves',              survex.survexcaveslist,     name="survexcaveslist"),

    path('survexfile/<path:survex_file>.svx', survex.svx,        name="svx"), 
    path('survexfile/<path:survex_file>.3d',  survex.threed,     name="threed"), 
    path('survexfile/<path:survex_file>.log', survex.svxlog,     name="svxlog"),  
    path('survexfile/<path:survex_file>.err', survex.err,        name="err"), 
    path('survexfile/<path:cave_shortname>',  survex.survexcavesingle,    name="survexcavessingle"),

    path('survexfilewild',                statistics.svxfilewild, name="svxfilewild"),
    path('survexfilewild/<int:year>',     statistics.svxfilewild, name="svxfilewild"),

# The survey scans in the wallets. This short-cuts SCANS_URL which is not used anymore and is defunct
    path('survey_scans',                    allscans,    name="allscans"), # all the scans in all wallets
    path('survey_scans/<path:path>/',        walletedit,  name="singlewallet"), # replaced singlewallet()
    path('survey_scans/<path:path>/<file>',  scansingle,  name="scansingle"), # works, but html href goes direct to /expofiles/ too
    path('cave/scans/<slug:caveid>',         cavewallets, name="cavewallets"), # like allscans, but for just one cave
    
# The data about the wallets themselves, not the scans inside them 
    path('wallets/year/<int:year>',       walletslistyear,  name="walletslistyear"), # wallets that are for a specific year, as an integer '1985'
    path('wallets/person/<slug:slug>',   walletslistperson,  name="walletslistperson"), 

# The tunnel and therion drawings files pageswalletslistcave
    path('drawings',                      dwgallfiles,       name="dwgallfiles"), 
    path('dwgfiles',                      dwgallfiles,       name="dwgallfiles"), 
    path('dwgdataraw/<path:path>',        dwgfilesingle,     name="dwgfilesingle"), 

# QMs pages - must precede other /caves pages?
    re_path(r'^cave/qms/([^/]+)/?$', caveQMs, name="caveQMs"),
    re_path(r'^cave/openqms/([^/]+)/?$', caveQMs, {'open': True}, name="cave_openQMs"),
    re_path(r'^cave/qms/(?P<cave_id>[^/]+)/(?P<year>\d\d\d\d)-(?P<qm_id>\d*)(?P<grade>[ABCDXV\?]?)-?(?P<blockname>[a-zA-Z]+.*)?$', qm, name="qm"), # Dogs breakfast
    # the  resolution of a QM uses several fields together, there is no clean slug field. Artefact of history.

#   Prospecting Guide document
    re_path(r'^prospecting_guide/$', prospecting),    # disabled. Bad links, incompatible image package use and very, very out of date.

# This next set are all intercepted by Apache, if it is running, with no problem.
    re_path(r'^photos/(?P<subpath>.*)$',      mediapage, {'doc_root': settings.PHOTOS_ROOT}, name="mediapage"), # photo galleries 
    re_path(r'^map/slippy/map.html', map,     name="map"), # Redirects to OpenStreetMap JavaScript. NOT WORKING
    re_path(r'^map/(?P<path>.*)$',     mapfile, name="mapfile"),  # css, js, gpx. working. This does not add any troggle menus or headers

# This next set are all intercepted by Apache, if it is running, AND troggle must manage these, 
# even though the code is not in the troggle repo
# Alias /static/ /home/expo/static/
    re_path(r'^static/(?P<subpath>.*)$',      mediapage, {'doc_root': settings.MEDIA_ROOT},  name="mediapage"), # STATIC only used by admin pages
# Alias /javascript /usr/share/javascript
    path('javascript/<path:subpath>',  mediapage, {'doc_root': settings.JSLIB_ROOT},  name="mediapage"), # JSLIB_URL 
    

    
# Helpers to edit HTML
    re_path(r'^image_selector/(?P<path>.*)', image_selector, name = 'image_selector'),
    re_path(r'^new_image_form/(?P<path>.*)', new_image_form, name = 'new_image_form'),
    
    re_path(r'^expo.kml', expo_kml, name = 'expo.kml'),
    re_path(r'^expo.kmz', expo_kmz, name = 'expo.kmz'),

# Final catchall which also serves expoweb handbook pages and imagestiny
# but a universal catchall also prevents the djang standard append_slash working, as every string resolves. 
# try to fix in troggle/middleware.py 
    re_path(r'^(.*)$',              expopage,     name="expopage"),     # CATCHALL assumed relative to EXPOWEB. This means APPEND_SLASH never works.
]

# do NOT allow DIR_ROOT prefix to all urls

#urlpatterns = static(settings.JSLIB_URL, document_root=settings.JSLIB_ROOT) #For development purposes, in production this should be served statically perhaps from /usr/share/javascript
#urlpatterns += static(settings.EXPOWEBCACHE_URL, document_root=settings.EXPOWEBCACHE_ROOT) #For development purposes, in production this should be served statically
urlpatterns = [re_path('', include(trogglepatterns))]

# When apache is running these prempt Django so Django never sees them.
# NB apache has its own ideas about mimetypes, so behaviour may not be identical for .xml files by troggle
# These directives are in /home/expo/config/apache/expo.conf  on the server
# checked as correct 3 May 2023.

#These are the critical ones: /static/ and /javascript/
#Note that apache does NOT intercept /site-media/
# Alias /static/ /home/expo/static/
# Alias /javascript /usr/share/javascript
#
# Alias /expofiles /home/expo/expofiles
# Alias /photos /home/expo/webphotos
# Alias /map /home/expo/expoweb/map
# Alias /expowebcache /home/expo/expowebcache/ # no longer used
# Alias /robots.txt /home/expo/static/robots.txt
# Alias /favicon.ico /home/expo/static/favicon.ico

#This is archaic ?
# Redirect permanent "/expoimages/" "/expofiles/"

# #kanboard, the trello-clone, but need individual user id to be effective
# Alias /kanboard /home/expo/kanboard

# #Search function (xapian-omega)
# ScriptAlias /search /usr/lib/cgi-bin/omega/omega

# ScriptAlias /hgrepositories /home/expo/config/apache/services/hgweb/hgweb.cgi

# #bank of expo
# #current expedition
# ScriptAlias "/boe" "/home/expo/boe/boc/boc.pl"
# #archived expedition boe instances
# ScriptAliasMatch "^/boe-(.*)" "/home/expo/boe/boc-$1/boc.pl"



