"""Plugin for adding checks to run on the worker node."""

import os
import re
from typing import List, TextIO
from arcnagios.ce.jobplugin import JobPlugin, StagingSpec
from arcnagios.nagutils import OK, CRITICAL, UNKNOWN, NagiosReport

_PRESENCE_SCRIPT = """\
missing=
for prog in %(required_programs)s; do
    type -p $prog >/dev/null 2>&1 || missing="$missing $prog"
done
if test -n "$missing"; then
    echo "__missing$missing" >%(output_file)s
else
    %(script_line)s
    err=$?
    [ $err -eq 0 ] || echo "__exit $err" >>%(output_file)s
fi
"""
_PLAIN_SCRIPT = """\
%(script_line)s
err=$?
[ $err -eq 0 ] || echo "__exit $err" >>%(output_file)s
"""

class ScriptedJobPlugin(JobPlugin):
    _missing_re = re.compile(r'__missing\s+(.*)')
    _exit_re = re.compile(r'__exit\s+(\d+)')
    _status_re = re.compile(r'__status\s+(\d+)\s+(.*)')
    _log_re = re.compile(r'__log\s+(\d+)\s+(.*)')

    def write_script(self, fh: TextIO, workdir: str) -> None:
        script_line = self.getconf_str('script_line')
        fh.write('# Scripted test %s\n'%self.service_description)
        output_file = self.getconf_str('output_file')
        env = {
            'script_line': script_line,
            'output_file': output_file
        }
        if self.hasconf('required_programs'):
            env['required_programs'] = self.getconf_str('required_programs')
            fh.write(_PRESENCE_SCRIPT % env)
        else:
            fh.write(_PLAIN_SCRIPT % env)
        fh.write('\n')

    def staged_inputs(self, workdir: str) -> List[StagingSpec]:
        specs = self.getconf_strlist('staged_inputs', default = [])
        return [StagingSpec.parse(spec, workdir) for spec in specs]

    def staged_outputs(self, workdir: str) -> List[StagingSpec]:
        spec = self.getconf_str('output_file')
        return [StagingSpec(spec, None, [])]

    def check(
            self, report: NagiosReport, jobdir: str, stored_urls: List[str]
        ) -> None:
        output_file = os.path.join(jobdir, self.getconf_str('output_file'))
        if self.hasconf('output_pattern'):
            pattern_re = re.compile(self.getconf_str('output_pattern'))
        else:
            pattern_re = None
        try:
            with open(output_file, encoding='utf-8') as fh:
                for line in fh:
                    if pattern_re:
                        mo = re.match(pattern_re, line)
                        if mo:
                            msg = self.getconf_str('status_ok',
                                                   subst=mo.groupdict())
                            report.update_status(OK, msg)
                            fh.close()
                            return
                    mo = re.match(self._missing_re, line)
                    if mo:
                        msg = 'Missing program(s) %s'%mo.group(1)
                        report.update_status(CRITICAL, msg)
                        break
                    mo = re.match(self._exit_re, line)
                    if mo:
                        code = int(mo.group(1))
                        if code:
                            msg = 'Script exited with code %d.'%code
                            report.update_status(CRITICAL, msg)
                            continue
                    mo = re.match(self._status_re, line)
                    if mo:
                        report.update_status(int(mo.group(1)), mo.group(2))
                        continue
                    mo = re.match(self._log_re, line)
                    if mo:
                        report.log.log(int(mo.group(1)), mo.group(2))
                        continue
        except IOError:
            report.update_status(UNKNOWN,
                    'Did not receive output file %s.'%output_file)
            return
        if pattern_re:
            report.update_status(CRITICAL,
                self.getconf_str('status_critical',
                                 default='Pattern not found.'))
