module runner

import os
import v.util.diff

const is_vautofix = os.getenv('VAUTOFIX') != ''

pub struct RunnerOptions {
pub:
	wd    string
	vexec string
	files []string
}

pub fn full_path_to_v(dirs_in int) string {
	vexe_from_env := os.getenv('VEXE')
	if vexe_from_env.len > 0 {
		return vexe_from_env
	}
	vname := if os.user_os() == 'windows' { 'v.exe' } else { 'v' }
	mut path := os.executable()
	for i := 0; i < dirs_in; i++ {
		path = os.dir(path)
	}
	vexec := os.join_path(path, vname)
	/*
	args := os.args
	vreal  := os.real_path('v')
	myself := os.real_path( os.executable() )
	wd := os.getwd()
	println('args are: $args')
	println('vreal   : $vreal')
	println('myself  : $myself')
	println('wd      : $wd')
	*/
	return vexec
}

pub fn run_repl_file(wd string, vexec string, file string) !string {
	vexec_folder := os.dir(vexec) + os.path_separator
	fcontent := os.read_file(file) or { return error('Could not read repl file ${file}') }
	content := fcontent.replace('\r', '')
	input := content.all_before('===output===\n')
	output := content.all_after('===output===\n').trim_right('\n\r')
	fname := os.file_name(file)
	input_temporary_filename := os.real_path(os.join_path(wd, 'input_temporary_filename.txt'))
	os.write_file(input_temporary_filename, input) or { panic(err) }
	os.write_file(os.real_path(os.join_path(wd, 'original.txt')), fcontent) or { panic(err) }
	os.cp_all('vlib/v/slow_tests/repl/tmpl', os.real_path(os.join_path(wd, 'tmpl')), true) or {
		panic(err)
	}
	rcmd := '${os.quoted_path(vexec)} repl -replfolder ${os.quoted_path(wd)} -replprefix "${fname}." < ${os.quoted_path(input_temporary_filename)}'
	r := os.execute(rcmd)
	if r.exit_code != 0 {
		os.rm(input_temporary_filename)!
		return error('Could not execute: ${rcmd}')
	}
	result := r.output.replace_each(['\r', '', '>>> ', '', '>>>', '', '... ', '',
		wd + os.path_separator, '', vexec_folder, '', '\\', '/']).trim_right('\n\r')
	$if windows {
		dump(rcmd)
		dump(r.output)
		dump(result)
	}
	os.rm(input_temporary_filename)!
	if result != output {
		if is_vautofix {
			new_content := input + '===output===\n' + r.output.trim_right('\n\r') + '\n'
			os.write_file(file, new_content)!
			eprintln('>>> fixed file: `${file}`, new_content.len: ${new_content.len}')
		}
		return diff_error(file, output, result)
	}
	return file.replace('./', '')
}

pub fn run_prod_file(wd string, vexec string, file string) !string {
	file_expected := '${file}.expected.txt'
	f_expected_content := os.read_file(file_expected) or {
		return error('Could not read expected prod file ${file_expected}')
	}
	expected_content := f_expected_content.replace('\r', '')
	cmd := '${os.quoted_path(vexec)} -prod run ${os.quoted_path(file)}'
	r := os.execute(cmd)
	if r.exit_code < 0 {
		return error('Could not execute: ${cmd}')
	}
	if r.exit_code != 0 {
		return error('${cmd} return exit code: ${r.exit_code}')
	}
	result := r.output.replace('\r', '')
	if result != expected_content {
		return diff_error(file, expected_content, result)
	}
	return 'Prod file ${file} is OK'
}

pub fn new_options() RunnerOptions {
	vexec := full_path_to_v(5)
	mut wd := os.getwd()
	mut files := []string{}
	if os.args.len > 1 {
		files = os.args[1..].clone()
	} else {
		os.chdir(os.dir(vexec)) or {}
		wd = os.getwd()
		files = os.walk_ext('.', '.repl')
	}
	return RunnerOptions{
		wd:    wd
		vexec: vexec
		files: files
	}
}

pub fn new_prod_options() RunnerOptions {
	wd := os.getwd()
	vexec := full_path_to_v(4)
	mut files := []string{}
	if os.args.len > 1 {
		files = os.args[1..].clone()
	} else {
		files = os.walk_ext(wd, '.prod.v')
	}
	return RunnerOptions{
		wd:    wd
		vexec: vexec
		files: files
	}
}

fn diff_error(file string, expected string, found string) IError {
	header := 'Difference found in REPL file: ${file}'
	details := if diff_ := diff.compare_text(expected, found) {
		'
====> Diff     :
${diff_}
'
	} else {
		'
====> Expected :
|${expected}|
====> Got      :
|${found}|
'
	}
	return error(header + details)
}
