#!/usr/bin/env python
# -*- coding:utf-8 -*-
import datetime
from threading import Lock

import time


class Timing:
    def __init__(self, sleep_interval=3):
        self.task = {}
        self.lock = Lock()
        self.sleep_interval = sleep_interval

    def add_task(self, task_id, name, interval, func, *args, **kwargs):
        """
        Add a timing task and schedule will execute it.
        :param task_id: Unique task id.
        :param name: Task name.
        :param interval: The interval between the next task execution.
        :param func: The function of timing task execution.
        :return:
        """
        if not isinstance(task_id, str):
            raise TypeError('task_id must be str')
        if not isinstance(interval, int):
            raise TypeError('interval must be int')
        if interval < 0:
            raise ValueError('interval must be bigger than 0')
        if not isinstance(func, function):
            raise TypeError('func must be func')

        self.lock.acquire()
        self.task[task_id] = {'name': name, 'interval': interval, 'func': func, 'args': args, 'kwargs': kwargs}
        self.lock.release()

    def delete_task(self, task_id):
        """
        Delete the task from schedule by task_id, if exist, return it.
        :param task_id: Unique task id.
        :return:
        """
        element = None
        self.lock.acquire()
        if self.task.__contains__(task_id):
            element = self.task.pop(task_id)
        self.lock.release()
        return element

    def set_interval(self, interval):
        self.sleep_interval = interval

    def sleep(self):
        time.sleep(self.sleep_interval)

    def run(self):
        while True:
            self.lock.acquire()
            for task_id, task_detail in self.task.keys():
                now = int(datetime.datetime.now().timestamp() * 1000)
                interval = task_detail['interval']
                if interval - (now % interval) > 1:
                    continue
                task_detail['func']()
            self.lock.release()
            self.sleep()


defaultTiming = Timing()


def add_task(task_id, name, interval, func, *args, **kwargs):
    defaultTiming.add_task(task_id, name, interval, func, *args, **kwargs)


def delete_task(task_id):
    defaultTiming.delete_task(task_id)


def set_interval(interval):
    defaultTiming.set_interval(interval)


def run():
    defaultTiming.run()