#對整個應用做初始化操作
#主要工作：
# 1.構建Flask的應用以及各種配置
#2.構建SQLAlchemy的應用

from flask import Flask, g
from flask_sqlalchemy import SQLAlchemy
import pymysql
import eventlet
from flask_mqtt import Mqtt
from flask_migrate import Migrate
#from flask_migrate import Migrate, MigrateCommand
from flask_babel import Babel
from werkzeug.wrappers import request


#綠化(綠色線程)所有系統模組，實現IO多路複用
# eventlet.monkey_patch()

pymysql.install_as_MySQLdb()



def register_i18n(app):
    """Register i18n with the Flask application."""
    defalut_language_str = app.config['DEFAULT_LANGUAGE']
    support_language_list = app.config['SUPPORTED_LANGUAGES']

    # 1. 取得子資料夾路徑 land_code
    @app.url_value_preprocessor
    def get_lang_code(endpoint, values):
        if values is not None:
            g.lang_code = values.pop('lang_code', defalut_language_str)

    # 2. 確認 config 內包含 lang_code
    @app.before_request
    def ensure_lang_support():
        lang_code = g.get('lang_code', None)
        if lang_code and lang_code not in support_language_list:
            g.lang_code = request.accept_languages.best_match(support_language_list)

    # 3. 設定多語系
    @app.localeselector
    def get_locale():
        return g.get('lang_code')

    # 4. 確認在 1. pop lang_code 參數後的 lang_code 值
    @app.url_defaults
    def set_langrage_code(endpoint, values):
        if 'lang_code' in values or not g.lang_code:
            return
        if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
            values['lang_code'] = g.lang_code

def create_app():
    app = Flask(__name__)
    #配置啟動模式為調適模式
    # app.config['DEBUG'] = True
    #配置數據庫的連接字符串
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://coffee:skyeye@52.69.200.169:3306/Coffee'
    #配置數據庫內容再更新時自動提交
    app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
    #配置session所需要的秘鑰
    app.config['SECRET_KEY'] = 'you guess'

    # template 有修改後，會自動去更新
    app.config['TEMPLATES_AUTO_RELOAD'] = True

    #如果设置成True(默认情况)，Flask - SQLAlchemy将会追踪对象的修改并且发送信号。这需要额外的内存， 如果不必要的可以禁用它
    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True

    #資料库连接池的大小。默认是数据库引擎的默认值 （通常是5）
    app.config['SQLALCHEMY_POOL_SIZE'] = 100

    #指定資料库连接池的超时时间。默认是 10
    # app.config['SQLALCHEMY_POOL_TIMEOUT'] = 60
    app.config['SQLALCHEMY_POOL_TIMEOUT'] = 60 * 60

    #自动回收连接的秒数。这对 MySQL 是必须的，默认 情况下 MySQL 会自动移除闲置 8 小时或者以上的连接。 需要注意地是如果使用 MySQL 的话， Flask-SQLAlchemy 会自动地设置这个值为 2 小时
    app.config['SQLALCHEMY_POOL_RECYCLE'] = 60 * 60 * 8
    
    app.config['SQLALCHEMY_MAX_OVERFLOW'] = 15

    # app.config['SECRET'] = 'my secret key'
    #MQTT相關設置
    app.config['MQTT_BROKER_URL'] = '60.250.156.234'
    app.config['MQTT_BROKER_PORT'] = 1883
    app.config['MQTT_USERNAME'] = 'aisky-client'
    app.config['MQTT_PASSWORD'] = 'aiskyc'
    #將發送ping到代理的時間間隔設置60秒
    app.config['MQTT_KEEPALIVE'] = 60
    #出於測試目的將TLS設置為禁用
    app.config['MQTT_TLS_ENABLED'] = False

    #資料庫的初始化
    db = SQLAlchemy(app)
    db.init_app(app)
    mqtt = Mqtt(app)

    # 初始化Flask-Migrate擴展
    migrate = Migrate(app, db)

    babel = Babel()
    register_blueprints(app)
    register_extensions(app)
    register_i18n(app)

    #用來使用flask-migrate數據遷移使用，如要用在把下面模型類註釋消掉，並且將main裡的from coffee_manage import mqtt,db註釋掉(因會報導入錯誤)
    # # 用戶表
    # class User(db.Model):
    #     __tablename__ = 'user'
    #
    #     userID = db.Column(db.Integer, primary_key=True)
    #     firstname = db.Column(db.String(30), nullable=False)
    #     lastname = db.Column(db.String(30), nullable=False)
    #     mail = db.Column(db.String(50), nullable=False)
    #     phone = db.Column(db.String(20), nullable=False)
    #     username = db.Column(db.String(30), nullable=False, unique=True)
    #     password = db.Column(db.String(40), nullable=False)
    #     status = db.Column(db.Integer, nullable=False, info='0:admin;1:new;9:disable')
    #
    # # 發酵槽溫度感測器表
    # class TankTemSensor(db.Model):
    #     __tablename__ = 'tank_tem_sensor'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     tank_num = db.Column(db.Integer, nullable=False)
    #     tem = db.Column(db.Text, nullable=False)
    #
    # # 發酵槽二氧化碳感測器表
    # class TankCO2Sensor(db.Model):
    #     __tablename__ = 'tank_co2_sensor'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     tank_num = db.Column(db.Integer, nullable=False)
    #     co2 = db.Column(db.Text, nullable=False)
    #
    # # 發酵槽酸鹼值感測器表
    # class TankPHSensor(db.Model):
    #     __tablename__ = 'tank_ph_sensor'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     tank_num = db.Column(db.Integer, nullable=False)
    #     ph = db.Column(db.Text, nullable=False)
    #
    # class BeanValve(db.Model):
    #     __tablename__ = 'bean_valve'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class WashMachine(db.Model):
    #     __tablename__ = 'wash_machine'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class ConveyorBelt1(db.Model):
    #     __tablename__ = 'conveyor_belt1'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class Cargo1Disinfect(db.Model):
    #     __tablename__ = 'cargo1_disinfect'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class ColorMachine(db.Model):
    #     __tablename__ = 'color_machine'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class ConveyorBelt2(db.Model):
    #     __tablename__ = 'conveyor_belt2'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class PeelingMachine(db.Model):
    #     __tablename__ = 'peeling_machine'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class ConveyorBelt3(db.Model):
    #     __tablename__ = 'conveyor_belt3'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class Bacteria(db.Model):
    #     __tablename__ = 'bacteria'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     tank_num = db.Column(db.Integer, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class Cargo2Disinfect(db.Model):
    #     __tablename__ = 'cargo2_disinfect'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     tank_num = db.Column(db.Integer, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class Heating(db.Model):
    #     __tablename__ = 'heating'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     tank_num = db.Column(db.Integer, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class Stir(db.Model):
    #     __tablename__ = 'stir'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     tank_num = db.Column(db.Integer, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class WaterInjection(db.Model):
    #     __tablename__ = 'water_injection'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     tank_num = db.Column(db.Integer, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class TopValve(db.Model):
    #     __tablename__ = 'top_valve'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     tank_num = db.Column(db.Integer, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class BottomValve(db.Model):
    #     __tablename__ = 'bottom_valve'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     tank_num = db.Column(db.Integer, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class Temperature(db.Model):
    #     __tablename__ = 'temperature'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     tank_num = db.Column(db.Integer, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class Hoist(db.Model):
    #     __tablename__ = 'hoist'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class Dryer(db.Model):
    #     __tablename__ = 'dryer'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     duration = db.Column(db.Text, nullable=False)
    #     start = db.Column(db.Text, nullable=False)
    #     end = db.Column(db.Text, nullable=False)
    #
    # class Relay(db.Model):
    #     __tablename__ = 'relay'
    #
    #     sn = db.Column(db.Integer, primary_key=True)
    #     datetime = db.Column(db.DateTime, nullable=False)
    #     tank_num = db.Column(db.Integer, nullable=False)
    #     status = db.Column(db.Text, nullable=False)




    #將main藍圖程序與app關聯到一起
    # from .main import main as main_blueprint
    # app.register_blueprint(main_blueprint)
    #將user藍圖程序與app關聯到一起
    from .user import user as user_blueprint
    app.register_blueprint(user_blueprint)

    # Rita 將lang藍圖程序與app關聯到一起
    from .main import main
    app.register_blueprint(main, url_prefix='/<lang_code>')

    return app, db, mqtt