import yaml

import must_triage.fs as fs
from . import base


class OCP(base.Inspector):
    gather_types = dict(
        yaml=dict(
            match=lambda p: fs.has_ext(p, ['yaml', 'yml']),
            description="Reading OCP YAML files",
        ),
    )

    @staticmethod
    def inspect_yaml(path):
        result = {path: list()}
        with open(path) as fd:
            try:
                obj = yaml.safe_load(fd)
            except (yaml.scanner.ScannerError, yaml.parser.ParserError):
                result[path].append("Failed to parse YAML content")
                return result
        if 'kind' in obj:
            result[path].extend(OCP.operator_success(obj))
            pods = list()
            if obj['kind'].lower() == 'pod':
                pods.append(obj)
            elif obj['kind'].lower() == 'podlist':
                pods.extend(filter(
                    lambda o: o['kind'].lower() == 'pod',
                    obj['items']
                ))
            result[path].extend(map(OCP.pod_ready, pods))
        if 'error' in obj:
            result[path].append(obj)
        return result

    @staticmethod
    def operator_success(obj):
        result = list()
        if obj['kind'] != 'ClusterServiceVersion':
            return result
        status = obj['status']
        if status['phase'].lower() == 'succeeded':
            return result
        result.append(
            f"Operator phase is '{status['phase']}', "
            "not 'Succeeded' as expected"
        )
        return result

    @staticmethod
    def pod_ready(obj):
        result = list()
        pod_name = obj['metadata']['name']
        status = obj['status']
        try:
            container_statuses = status['containerStatuses']
        except KeyError:
            return [dict(
                pod_name=pod_name,
                status=status,
                )]
        not_ready = filter(lambda cs: cs['ready'] is False, container_statuses)
        for cs in not_ready:
            ts = cs['state'].get('terminated', dict())
            if (ts.get('reason', '').lower() == 'completed' and
                    ts.get('exitCode') == 0):
                continue
            result.append(
                f"Container '{cs['name']}' in "
                f"pod '{pod_name}' is not ready")
            if 'waiting' in cs['state']:
                ws = cs['state'].get('waiting', dict())
                reason = ws.get('reason')
                if reason == 'PodInitializing':
                    ic_statuses = status.get('initContainerStatuses')
                    ics_notready = list(filter(
                        lambda ics: ics.get('ready') is False,
                        ic_statuses
                    ))
                    for ics in ics_notready:
                        result.append(
                            f"InitContainer '{ics['name']}' for container "
                            f"'{cs['name']}' in pod '{pod_name}' is not ready"
                        )
                        result.append(ics['state'])
                if reason == 'ImagePullBackOff':
                    result.append(ws)
                if reason == 'CrashLoopBackOff':
                    result.append(ws)
                    state = cs['lastState']
                    if 'terminated' in state:
                        result.append(dict(
                            message=state['terminated']['message']
                        ))
        return result
