import threading
import time

from flask import Flask, jsonify, abort, request

from bot import QWinBot
from db import QwinCasinoDao
from smartsupp import SmartsuppClient

app = Flask(__name__)

verbose = True

with app.app_context():
    qwin_bot = QWinBot(verbose=False)
    print('Qwin chat bot initialized')
    
    qwin_dao = QwinCasinoDao()
    print('Qwin dao initialized')
    
    smartsupp_client = SmartsuppClient(verbose=True)
    print('Smartsupp client initialized')
    
    
@app.route("/", methods=['GET', 'POST'])
def hello():
    return jsonify('Tezro support bot')

@app.route("/ping", methods=['GET', 'POST'])
def ping():
    return jsonify('OK') 

@app.route("/invoke", methods=['POST'])
def chat_bot_message():
    if request.is_json:
        req_data = request.get_json()
        seq = req_data['sequence']
        user_id = req_data['user_id']
        
        error, output = qwin_bot.invoke(user_id=user_id, query=seq)
        
        if error:
            return jsonify({'error': True, 'message': output})
        else:
            millis = round(time.time() * 1000) 
            
            return jsonify({'timestamp': millis,
                            'error': False,
                            'user_id': user_id,
                            'input_sentence': seq, 
                            'output_sequence': output})
        
    else:
        abort(400)
        
@app.route("/hook/message-sent", methods=['POST'])
def hook_message_sent():
    if request.is_json:
        req_data = request.get_json()
        thread = threading.Thread(target=handle_message_sent_hook, args=(req_data, True))
        thread.start()
        
        return jsonify({})
    else:
        abort(400)
        
def handle_message_sent_hook(hook_data, verbose=False):
    visitor_id = hook_data['data']['conversation']['visitor_id']
    conversation_id = hook_data['data']['conversation']['id']
    message_text = hook_data['data']['message']['content']['text']
    
    if verbose:
        print(f'Hook data - visitor: {visitor_id}, conv: {conversation_id}, text: {message_text}')
    
    visitor_name = smartsupp_client.visitor(visitor_id)
    
    if verbose:
        print(f'Visitor name: {visitor_name}')
    
    if visitor_name:
        user_id = qwin_dao.get_customer_id(visitor_name)
        if user_id:
            user_id = str(user_id)
        else:
            user_id = visitor_id
    else:
        user_id = 'anonymous'
        
    if verbose:
        print(f'User id: {user_id}')
        
    smartsupp_client.typing(conversation_id)    
    
    error, output = qwin_bot.invoke(user_id=user_id, query=message_text)
    
    if error:
        if error == -1:
            print('Operator requested')
        else:
            print(f'Bot error: {output}')

        smartsupp_client.send_message(conversation_id, 'Unexpected error, could you repeat the query please?')
    else:
        parts = split_output(output)
        for part in parts:
            smartsupp_client.send_message(conversation_id, part)

def split_output(output: str, max_length: int = 900) -> [str]:
    words = output.split(' ')
    parts = []
    current_part = []

    for word in words:
        if sum(len(w) for w in current_part) + len(current_part) + len(word) > max_length:
            parts.append(' '.join(current_part))
            current_part = [word]
        else:
            current_part.append(word)

    if current_part:
        parts.append(' '.join(current_part))

    return parts

if __name__ == "__main__":
    app.run(host='0.0.0.0')