#!/usr/bin/python3

import subprocess
from pathlib import Path
import tempfile
import os


def set_git_identity():
	"""Set local git identity, but only in local repo (to not overwrite user settings)"""
	subprocess.run(['git', 'config', 'user.name', 'James Bond'])
	subprocess.run(['git', 'config', 'user.email', '007@sis.gov.uk'])


def create_file(filename: str, file_content: str):
	"""Create a file in the current directory and adds it to git"""
	Path(filename).parent.mkdir(parents=True, exist_ok=True)
	with open(filename, "w") as textfile:
		print(file_content, file=textfile)
	subprocess.run(['git', 'add', filename], check=True)


class ScriptTest():
	def __init__(self, scriptpath: Path):
		self.scriptpath = Path(scriptpath)

	def __enter__(self):
		"""Create temporary, minimal test environment, and change to it"""
		self.lmms_tmpdir = tempfile.TemporaryDirectory(dir='.')
		os.chdir(self.lmms_tmpdir.name)
		# prerequirements
		Path('data/themes').mkdir(parents=True)
		subprocess.run(['git', 'init', '-b', 'main'], check=True)
		set_git_identity()
		subprocess.run(['git', 'submodule', 'add', '../../carla', 'plugins/CarlaBase/carla'], check=True)
		create_file('src/core/classes.cpp', 'namespace lmms {\nclass TestClass\n}')
		create_file('debian/lmms-common.docs', '')
		create_file('debian/copyright', '')
		create_file('data/locale/de.ts',
					'<?xml version="1.0" ?><!DOCTYPE TS><TS language="de" version="2.1">\n'
					'    <context>\n'
					'    <name>TestClass</name>\n'
					'     <message>\n'
					'        <location filename="../../src/core/classes.cpp" line="20"/>\n'
					'        <source>About LMMS</source>\n'
					'        <translation>Über LMMS</translation>\n'
					'    </message>\n'
					'</context>\n'
					'</TS>\n')
		subprocess.run(['git', 'commit', '-m', 'Initial commit'], check=True)
		return self

	def __exit__(self, type, value, traceback):
		"""Leave and destroy temporary test environment"""
		os.chdir('..')
		self.lmms_tmpdir.cleanup()

	def expect(self, expectation: str):
		"""Check if "expectation" is in the output"""
		if expectation not in self.result.stdout:
			raise RuntimeError(f'Expected "{expectation}" in script output')

	def run(self, expected_returncode: int = 1):  # default: something goes wrong ("to the safe side")
		"""Run the script, check the exit code and store the result"""
		self.result = subprocess.run([str(self.scriptpath)], capture_output=True, text=True)
		print('--->8--- Script output BEGIN --->8---')
		print(self.result.stdout)
		print('--->8--- Script output END   --->8---')
		if self.result.stderr:
			print('--->8--- Script error output BEGIN --->8---')
			print(self.result.stderr)
			print('--->8--- Script error output END   --->8---')
		# make sure script returned "error" (because we test for errors) and that the output is as expected
		if self.result.returncode != expected_returncode:
			raise RuntimeError(f"Script \"check-strings\" returned {self.result.returncode}, "
							   f"but {expected_returncode} expected")


lmms_main_path = Path(__file__).resolve().parent.parent.parent

with tempfile.TemporaryDirectory() as tmpdir:
	os.chdir(tmpdir)
	check_strings = lmms_main_path / 'tests' / 'scripted' / 'check-strings'

	# create dummy carla repo
	Path('carla').mkdir()
	os.chdir('carla')
	subprocess.run(['git', 'init', '-b', 'main'], check=True)
	set_git_identity()
	create_file('README.md', 'hello world')
	subprocess.run(['git', 'commit', '-m', 'Initial commit'], check=True)
	os.chdir('..')

	Path('lmms').mkdir()
	os.chdir('lmms')

	# minimal working example
	with ScriptTest(check_strings) as test:
		test.run(0)  # exitcode 0 - no errors expected
		test.expect('0 errors')

	with ScriptTest(check_strings) as test:
		create_file('data/locale/fr.ts',
					'<?xml version="1.0" ?><!DOCTYPE TS><TS language="de" version="2.1">\n'
					'    <context>\n'
					'    <name>TestClass</name>\n'
					'     <message>\n'
					'        <location filename="../../src/core/non-existent.cpp" line="20"/>\n'
					'        <source>About LMMS</source>\n'
					'        <translation>À propos de LMMS</translation>\n'
					'    </message>\n'
					'</context>\n'
					'</TS>\n')
		test.run()
		test.expect('Error: data/locale: Source file does not exist: ../../src/core/non-existent.cpp')
		test.expect('1 errors')

	with ScriptTest(check_strings) as test:
		create_file('data/locale/fr.ts',
					'<?xml version="1.0" ?><!DOCTYPE TS><TS language="de" version="2.1">\n'
					'    <context>\n'
					'    <name>NonExistentClass</name>\n'
					'     <message>\n'
					'        <location filename="../../src/core/classes.cpp" line="20"/>\n'
					'        <source>About LMMS</source>\n'
					'        <translation>À propos de LMMS</translation>\n'
					'    </message>\n'
					'</context>\n'
					'</TS>\n')
		test.run()
		test.expect('Error: data/locale: Class does not exist in source code: NonExistentClass')
		test.expect('1 errors')

	with ScriptTest(check_strings) as test:
		create_file('data/themes/classic/style.css',
					'lmms--gui--NonExistentClass {'
					'\tcolor: #d1d8e4;\n'
					'}')
		test.run()
		test.expect('Error: data/themes/classic/style.css: Class does not exist in source code: NonExistentClass')
		test.expect('1 errors')

	with ScriptTest(check_strings) as test:
		create_file('debian/patches/clang.patch', '/plugins/non-existent-file')
		test.run()
		test.expect('Error: debian/patches/clang.patch: Source file does not exist: plugins/non-existent-file')
		test.expect('1 errors')

	with ScriptTest(check_strings) as test:
		create_file('debian/lmms-common.docs', '/plugins/caps.html')
		test.run()
		test.expect('Error: debian/lmms-common.docs: Path does not exist: /plugins/caps.html')
		test.expect('1 errors')

	with ScriptTest(check_strings) as test:
		create_file('debian/copyright', 'Files: NonExistent')
		test.run()
		test.expect('Error: debian/copyright: Glob/Path does not exist: NonExistent')
		test.expect('1 errors')

# if we made it until here without an exception, all tests have been passed
print("SUCCESS")
