# -*- coding: utf-8 -*-
import json
import re
from os import path

# 12306 账号
from py12306.helpers.func import *


@singleton
class Config:
    IS_DEBUG = False

    USER_ACCOUNTS = []
    # 查询任务
    QUERY_JOBS = []
    # 查询间隔
    QUERY_INTERVAL = 1
    # 用户心跳检测间隔
    USER_HEARTBEAT_INTERVAL = 120
    # 多线程查询
    QUERY_JOB_THREAD_ENABLED = 0
    # 打码平台账号
    AUTO_CODE_PLATFORM = ''
    AUTO_CODE_ACCOUNT = {'user': '', 'pwd': ''}
    # 输出日志到文件
    OUT_PUT_LOG_TO_FILE_ENABLED = 0
    OUT_PUT_LOG_TO_FILE_PATH = 'runtime/12306.log'

    SEAT_TYPES = {'特等座': 25, '商务座': 32, '一等座': 31, '二等座': 30, '软卧': 23, '硬卧': 28, '硬座': 29, '无座': 26, }

    ORDER_SEAT_TYPES = {'特等座': 'P', '商务座': 9, '一等座': 'M', '二等座': 'O', '软卧': 4, '硬卧': 3, '硬座': 1, '无座': 1}

    PROJECT_DIR = path.dirname(path.dirname(path.abspath(__file__))) + '/'

    # Query
    RUNTIME_DIR = PROJECT_DIR + 'runtime/'
    QUERY_DATA_DIR = RUNTIME_DIR + 'query/'
    USER_DATA_DIR = RUNTIME_DIR + 'user/'
    USER_PASSENGERS_FILE = RUNTIME_DIR + 'user/%s_passengers.json'

    STATION_FILE = PROJECT_DIR + 'data/stations.txt'
    CONFIG_FILE = PROJECT_DIR + 'env.py'

    # 语音验证码
    NOTIFICATION_BY_VOICE_CODE = 0
    NOTIFICATION_VOICE_CODE_TYPE = ''
    NOTIFICATION_VOICE_CODE_PHONE = ''
    NOTIFICATION_API_APP_CODE = ''

    # 集群配置
    CLUSTER_ENABLED = 0
    NODE_SLAVE_CAN_BE_MASTER = 1
    NODE_IS_MASTER = 1
    NODE_NAME = ''
    REDIS_HOST = ''
    REDIS_PORT = '6379'
    REDIS_PASSWORD = ''

    # 钉钉配置
    DINGTALK_ENABLED = 0
    DINGTALK_WEBHOOK = ''

    # Telegram推送配置
    TELEGRAM_ENABLED = 0
    TELEGRAM_BOT_API_URL = ''

    # Bark 推送配置
    BARK_ENABLED = 0
    BARK_PUSH_URL = ''

    # ServerChan和PushBear配置
    SERVERCHAN_ENABLED = 0
    SERVERCHAN_KEY = '8474-ca071ADSFADSF'
    PUSHBEAR_ENABLED = 0
    PUSHBEAR_KEY = 'SCUdafadsfasfdafdf45234234234'

    # 邮箱配置
    EMAIL_ENABLED = 0
    EMAIL_SENDER = ''
    EMAIL_RECEIVER = ''
    EMAIL_SERVER_HOST = ''
    EMAIL_SERVER_USER = ''
    EMAIL_SERVER_PASSWORD = ''

    WEB_ENABLE = 0
    WEB_USER = {}
    WEB_PORT = 8080
    WEB_ENTER_HTML_PATH = PROJECT_DIR + 'py12306/web/static/index.html'

    # CDN
    CDN_ENABLED = 0
    CDN_CHECK_TIME_OUT = 2
    CDN_ITEM_FILE = PROJECT_DIR + 'data/cdn.txt'
    CDN_ENABLED_AVAILABLE_ITEM_FILE = QUERY_DATA_DIR + 'available.json'

    # Default time out
    TIME_OUT_OF_REQUEST = 5

    envs = []
    retry_time = 5
    last_modify_time = 0

    disallow_update_configs = [
        'CLUSTER_ENABLED',
        'NODE_IS_MASTER',
        'NODE_NAME',
        'REDIS_HOST',
        'REDIS_PORT',
        'REDIS_PASSWORD',
    ]

    def __init__(self):
        self.init_envs()
        self.last_modify_time = get_file_modify_time(self.CONFIG_FILE)
        if Config().is_slave():
            self.refresh_configs(True)
        else:
            create_thread_and_run(self, 'watch_file_change', False)

    @classmethod
    def run(cls):
        self = cls()
        self.start()

    # @classmethod
    # def keep_work(cls):
    #     self = cls()

    def start(self):
        self.save_to_remote()
        create_thread_and_run(self, 'refresh_configs', wait=Const.IS_TEST)

    def refresh_configs(self, once=False):
        if not self.is_cluster_enabled(): return
        while True:
            remote_configs = self.get_remote_config()
            self.update_configs_from_remote(remote_configs, once)
            if once or Const.IS_TEST: return
            stay_second(self.retry_time)

    def get_remote_config(self):
        if not self.is_cluster_enabled(): return
        from py12306.cluster.cluster import Cluster
        return Cluster().session.get_pickle(Cluster().KEY_CONFIGS, {})

    def save_to_remote(self):
        if not self.is_master(): return
        from py12306.cluster.cluster import Cluster
        Cluster().session.set_pickle(Cluster().KEY_CONFIGS, self.envs)

    def init_envs(self):
        self.envs = EnvLoader.load_with_file(self.CONFIG_FILE)
        self.update_configs(self.envs)

    def update_configs(self, envs):
        for key, value in envs:
            setattr(self, key, value)

    def watch_file_change(self):
        """
        监听配置文件修改
        :return:
        """
        if Config().is_slave(): return
        from py12306.log.common_log import CommonLog
        while True:
            value = get_file_modify_time(self.CONFIG_FILE)
            if value > self.last_modify_time:
                self.last_modify_time = value
                CommonLog.add_quick_log(CommonLog.MESSAGE_CONFIG_FILE_DID_CHANGED).flush()
                envs = EnvLoader.load_with_file(self.CONFIG_FILE)
                self.update_configs_from_remote(envs)
                if Config().is_master():  # 保存配置
                    self.save_to_remote()
            stay_second(self.retry_time)

    def update_configs_from_remote(self, envs, first=False):
        if envs == self.envs: return
        from py12306.query.query import Query
        from py12306.user.user import User
        from py12306.helpers.cdn import Cdn
        self.envs = envs
        for key, value in envs:
            if key in self.disallow_update_configs: continue
            if value != -1:
                old = getattr(self, key)
                setattr(self, key, value)
                if not first and old != value:
                    if key == 'USER_ACCOUNTS':
                        User().update_user_accounts(auto=True, old=old)
                    elif key == 'QUERY_JOBS':
                        Query().update_query_jobs(auto=True)  # 任务修改
                    elif key == 'QUERY_INTERVAL':
                        Query().update_query_interval(auto=True)
                    elif key == 'CDN_ENABLED':
                        Cdn().update_cdn_status(auto=True)

    @staticmethod
    def is_master():  # 是不是 主
        from py12306.cluster.cluster import Cluster
        return Config().CLUSTER_ENABLED and (Config().NODE_IS_MASTER or Cluster().is_master)

    @staticmethod
    def is_slave():  # 是不是 从
        return Config().CLUSTER_ENABLED and not Config.is_master()

    @staticmethod
    def is_cluster_enabled():
        return Config().CLUSTER_ENABLED

    @staticmethod
    def is_cdn_enabled():
        return Config().CDN_ENABLED


class EnvLoader:
    envs = []

    def __init__(self):
        self.envs = []

    @classmethod
    def load_with_file(cls, file):
        self = cls()
        if path.exists(file):
            env_content = open(file, encoding='utf8').read()
            content = re.sub(r'^([A-Z]+)_', r'self.\1_', env_content, flags=re.M)
            exec(content)
        return self.envs

    def __setattr__(self, key, value):
        super().__setattr__(key, value)
        if re.search(r'^[A-Z]+_', key):
            self.envs.append(([key, value]))
