"""
We are using unittest for troggle.

Note that the database has not been parsed from the source files when these tests are run,
so any path that relies on data being in the database will fail.

The simple redirections to files which exist, e.g. in
/expoweb/
/expofiles/
/expofiles/documents/
etc. will test fine.

But paths like this:
/survey_scans/
/caves/
which rely on database resolution will fail unless a fixture has been set up for
them.

https://docs.djangoproject.com/en/dev/topics/testing/tools/
"""
import re
import subprocess
import unittest

from django.test import Client, SimpleTestCase, TestCase


class SimpleTest(SimpleTestCase):
    def test_test_setting(self):
        from django.conf import settings

        self.assertEqual(settings.EMAIL_BACKEND, "django.core.mail.backends.locmem.EmailBackend")
        import troggle.settings as settings

    def test_import_TroggleModel(self):
        from troggle.core.models.troggle import TroggleModel

    def test_import_Cave(self):
        from troggle.core.models.caves import Cave

    def test_import_parsers_surveys(self):
        # from PIL import Image
        from functools import reduce

        from troggle.core.utils import save_carefully

    def test_import_parsers_survex(self):
        import troggle.core.models.caves as models_caves
        import troggle.core.models.survex as models_survex
        import troggle.core.models.troggle as models
        import troggle.settings as settings
        from troggle.core.views import caves, drawings, other, scans, statistics, survex, uploads
        from troggle.core.views.caves import cavepage, ent
        from troggle.core.views.other import frontpage
        from troggle.parsers.people import GetPersonExpeditionNameLookup

    def test_import_views_uploads(self):
        from troggle.core.views.uploads import dwgupload

    def test_import_views_walletedit(self):
        from troggle.core.views.wallets_edit import walletedit

    def test_import_parsers_QMs(self):
        from troggle.core.models.logbooks import QM

    def test_import_parsers_people(self):
        from html import unescape

        from unidecode import unidecode

    def test_import_parsers_logbooks(self):
        from django.template.defaultfilters import slugify
        from django.utils.timezone import get_current_timezone, make_aware

        from parsers.people import GetPersonExpeditionNameLookup
        from troggle.core.models.logbooks import CaveSlug, QM, LogbookEntry, PersonLogEntry
        from troggle.core.models.troggle import DataIssue, Expedition

    def test_import_core_views_caves(self):
        from django.conf import settings
        from django.contrib.auth.decorators import login_required
        from django.http import HttpResponse, HttpResponseRedirect
        from django.shortcuts import get_object_or_404, render

        import troggle.core.views.expo
        from troggle.core.forms import CaveAndEntranceFormSet, CaveForm, EntranceForm, EntranceLetterForm
        from troggle.core.models.caves import Area, Cave, CaveAndEntrance, Entrance, EntranceSlug, SurvexStation
        from troggle.core.models.troggle import Expedition
        from troggle.core.views.auth import login_required_if_public

    def test_import_parsers_mix(self):
        import troggle.parsers.caves
        import troggle.parsers.drawings
        import troggle.parsers.logbooks
        import troggle.parsers.people
        import troggle.parsers.QMs
        import troggle.parsers.scans
        import troggle.parsers.survex
        import troggle.settings
        from troggle.parsers.logbooks import GetCaveLookup

    def test_import_imports(self):
        from django.contrib.auth.models import User
        from django.core import management
        from django.db import close_old_connections, connection, connections
        from django.http import HttpResponse
        from django.urls import reverse

    def test_import_urls(self):
        from django.conf import settings
        #from django.conf.urls import include, url
        from django.contrib import admin, auth
        from django.urls import resolve, reverse
        from django.views.generic.base import RedirectView
        from django.views.generic.edit import UpdateView
        from django.views.generic.list import ListView

        from troggle.core.views import caves, other, statistics, survex
        from troggle.core.views.auth import expologin, expologout
        from troggle.core.views.caves import cavepage, ent
        from troggle.core.views.expo import (
            editexpopage,
            expofiles_redirect,
            expofilessingle,
            expopage,
            map,
            mapfile,
            mediapage,
        )
        from troggle.core.views.logbooks import (
            Expeditions_jsonListView,
            Expeditions_tsvListView,
            expedition,
            get_logbook_entries,
            get_people,
            logbookentry,
            notablepersons,
            person,
            personexpedition,
        )
        from troggle.core.views.other import controlpanel
        from troggle.core.views.prospect import prospecting, prospecting_image
        from troggle.core.views.statistics import dataissues, pathsreport, stats
        from troggle.core.views.survex import survexcavesingle, survexcaveslist, svx

class ImportTest(TestCase):
    @classmethod
    def setUpTestData(cls):
        import troggle.settings as settings
        from troggle.parsers.logbooks import LOGBOOKS_DIR, DEFAULT_LOGBOOK_FILE    
        
        LOGBOOKS_PATH = settings.EXPOWEB / LOGBOOKS_DIR 
        test_year = "1986"
        cls.test_logbook = LOGBOOKS_PATH / test_year / DEFAULT_LOGBOOK_FILE

    def setUp(self):
        pass

    def tearDown(self):
        pass

    def test_logbook_exists(self):
        self.assertTrue(self.test_logbook.is_file())


class SubprocessTest(TestCase):
    @classmethod
    def setUpTestData(cls):
        pass

    def setUp(self):
        pass

    def tearDown(self):
        pass

    def test_utf8(self):
        """Expects that utf8 is the default encoding when opening files"""
        import locale
        import sys

        self.assertTrue(
            sys.getdefaultencoding() == "utf-8", f"{sys.getdefaultencoding()} - UTF8 error in getdefaultencoding"
        )
        self.assertTrue(
            sys.getfilesystemencoding() == "utf-8",
            f"{sys.getfilesystemencoding()} - UTF8 error in getfilesystemencoding",
        )
        self.assertTrue(
            locale.getdefaultlocale()[1] == "UTF-8",
            f"{locale.getdefaultlocale()} - UTF8 error in locale.getdefaultlocale",
        )
        self.assertTrue(
            locale.getpreferredencoding() == "UTF-8",
            f"{locale.getpreferredencoding()} - UTF8 error in locale.getpreferredencoding",
        )

    def test_installs(self):
        """Expects external software installed: cavern, survexport, git
        (but not whether it actually works)
        """
        import troggle.settings as settings

        for i in [settings.CAVERN, settings.SURVEXPORT, settings.GIT]:
            # Define command as string and then split() into list format
            cmd = f"which {i}".split()
            try:
                sp = subprocess.check_call(cmd, shell=False)
            except subprocess.CalledProcessError:
                self.assertTrue(False, f"no {i} installed")

    def test_repos_git_status(self):
        """Expects clean git repos with no added files and no merge failures"""
        from pathlib import Path

        import troggle.settings as settings

        TROGGLE_PATH = Path(settings.REPOS_ROOT_PATH) / "troggle"
        for cwd in [settings.SURVEX_DATA, settings.EXPOWEB, settings.DRAWINGS_DATA, TROGGLE_PATH]:
            sp = subprocess.run([settings.GIT, "status"], cwd=cwd, capture_output=True, text=True)
            out = str(sp.stdout)
            if len(out) > 160:
                out = out[:75] + "\n <Long output curtailed>\n" + out[-75:]
            print(f"git output: {cwd}:\n # {sp.stderr=}\n # sp.stdout={out} \n # return code: {str(sp.returncode)}")
            if sp.returncode != 0:
                print(f"git output: {cwd}:\n # {sp.stderr=}\n # sp.stdout={out} \n # return code: {str(sp.returncode)}")

            self.assertTrue(sp.returncode == 0, f"{cwd} - git is unhappy")

            content = sp.stdout
            ph = r"Your branch is up[ -]to[ -]date"
            phmatch = re.search(ph, content)
            msg = f'{cwd} - Failed to find expected git output: "{ph}"'
            self.assertIsNotNone(phmatch, msg)

            ph1 = r"no changes added to commit"
            phmatch1 = re.search(ph1, content)
            ph2 = r"nothing to commit"
            phmatch2 = re.search(ph2, content)
            phmatch = phmatch1 or phmatch2
            msg = f'{cwd} - Failed to find expected git output: "{ph1}" or "{ph2}"'
            self.assertIsNotNone(phmatch, msg)

    def test_loser_survex_status(self):
        """Expects no failures of survex files"""
        from pathlib import Path

        import troggle.settings as settings

        cwd = settings.SURVEX_DATA
        for survey in ["1623.svx", "1626.svx"]:
            sp = subprocess.run([settings.CAVERN, survey], cwd=cwd, capture_output=True, text=True)
            out = str(sp.stdout)
            if len(out) > 160:
                out = out[:75] + "\n <Long output curtailed>\n" + out[-75:]
            # print(f'survex output: {cwd}:\n # {sp.stderr=}\n # sp.stdout={out} \n # return code: {str(sp.returncode)}')
            if sp.returncode != 0:
                print(
                    f"survex output: {cwd}:\n # {sp.stderr=}\n # sp.stdout={out} \n # return code: {str(sp.returncode)}"
                )

            self.assertTrue(sp.returncode == 0, f"{cwd} - survex is unhappy")

            content = sp.stdout
            ph = r"Total length of survey legs"
            phmatch = re.search(ph, content)
            msg = f'{cwd} - Failed to find expected survex output: "{ph}"'
            self.assertIsNotNone(phmatch, msg)

            ph1 = r"Time used"
            phmatch1 = re.search(ph1, content)
            ph2 = r"vertical length of survey le"
            phmatch2 = re.search(ph2, content)

            phmatch = phmatch1 or phmatch2
            msg = f'{cwd} - Failed to find expected survex output: "{ph1}" or "{ph2}"'
            self.assertIsNotNone(phmatch, msg)
