# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
# 
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#     http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from collections import OrderedDict
from .container import Container

from .status import Status

import random
import time


class PodSepc(object):
    def __init__(self):
        self._name = ''.join(
            random.choice('abcdefghijklmnopqrstuvwxyz') for _ in range(6))

        # by controller
        self._init_containers: List[Container] = []
        self._containers: List[Container] = []

        #self.resource: Resource = None
        #self.status: Status = None

        self._rank = -1
        self._init_timeout = 120  # 2 min timeout for each init container
        self._restart = -1
        self._replicas = 0  # number of containers
        self._exit_code = 0


class Pod(PodSepc):
    def __init__(self):
        super().__init__()

    def __str__(self):
        return "Pod: {}, replicas {}, status {}".format(self.name,
                                                        self.replicas,
                                                        self.status())

    def failed_container(self):
        for c in self._containers:
            if c.status() == Status.FAILED:
                return c
        return None

    @property
    def name(self):
        return self._name

    @property
    def replicas(self):
        return self._replicas

    @replicas.setter
    def replicas(self, r):
        self._replicas = r

    @property
    def rank(self):
        return self._rank

    @rank.setter
    def rank(self, r):
        self._rank = r

    @property
    def restart(self):
        return self._restart

    @property
    def containers(self):
        return self._containers

    def add_container(self, c):
        c.rank = len(self._containers)
        self._containers.append(c)

    @property
    def init_containers(self):
        return self._init_containers

    def add_init_container(self, c):
        c.rank = len(self._init_containers)
        self._init_containers.append(c)

    @property
    def exit_code(self):
        for c in self._containers:
            if c.exit_code() != 0:
                return c.exit_code()
        return 0

    def deploy(self):
        for i in self._init_containers:
            i.start(self._init_timeout)

        for c in self._containers:
            c.start()

        self._restart += 1

    def stop(self, sigint=0):
        for c in self._containers:
            force = True if sigint == 9 else False
            c.terminate(force)

    def join(self):
        for c in self._containers:
            c.wait(None)

    def status(self):
        if self.is_failed():
            return Status.FAILED

        if self.is_completed():
            return Status.COMPLETED

        return Status.READY

    def reset(self):
        self._init_containers = []
        self._containers = []

    def is_failed(self):
        for c in self._containers:
            if c.status() == Status.FAILED:
                return True
        return False

    def is_completed(self):
        for c in self._containers:
            if c.status() != Status.COMPLETED:
                return False
        return True

    def logs(self, idx=None):
        if idx is None:
            if self.failed_container():
                self.failed_container().logs()
            else:
                self._containers[0].logs()
        else:
            self._containers[idx].logs()

    def tail(self, idx=None):
        if idx is None:
            if self.failed_container():
                self.failed_container().tail()
            else:
                self._containers[0].tail()
        else:
            self._containers[idx].tail()

    def watch(self,
              all_list=[Status.COMPLETED],
              any_list=[Status.FAILED],
              interval=1,
              timeout=-1):
        '''
        watch return if any container status in any_list
        or all container status in all_list
        '''
        end = time.time() + timeout
        while timeout < 0 or time.time() < end:
            for c in self._containers:
                if c.status() in any_list:
                    return c.status()

            s = [c.status() for c in self._containers]
            if len(set(s)) == 1 and s[0] in all_list:
                return s[0]

            time.sleep(interval)
