# !/usr/bin/python3
# Built-in libraries
from pathlib import Path
import json
import os
from aiohttp import web
import aiohttp_cors
from multiprocessing import Process, cpu_count
from socket import SOL_SOCKET, SO_REUSEADDR, socket
#lan
from polyglot.detect import Detector
from pythainlp.tokenize import word_tokenize as th_word_tokenize

import  malaya
import spacy
from konlpy.tag import Mecab
from libs.app_tool import AppTool

nlp_en=spacy.load('en_core_web_sm')
nlp_zh=spacy.load('zh_core_web_sm')
nlp_xx=spacy.load("xx_ent_wiki_sm")

LISTEN_PORT = 8900

class NLPServer:
    def __init__(self):
        self.app_tool = AppTool('nlp.log')
        self.BASE_DIR = Path(__file__).parent
        self.ZK_CONF = self.app_tool.zk()
        self.hostname = os.uname()[1]
        self.logger = self.app_tool.logger

    def detect_text_lang(self, text):
        lang = Detector(text, quiet=True)
        return lang.language.code

    def text_segment(self, text):
        lang = self.detect_text_lang(text)
        word_list = []
        if lang == 'th':
            word_list = th_word_tokenize(text, engine="newmm")
        elif lang in ['zh_Hant', 'zh']:
            doc = nlp_zh(text)
            word_list = [chunk.text for chunk in doc]
        elif lang == 'ms':
            tokennizer = malaya.preprocessing.Tokenizer(text)
            word_list = tokennizer.tokenize(text)
        elif lang == 'ko':
            mecab = Mecab(dicpath='/usr/lib/mecab/dic/mecab-ko-dic')
            word_list = mecab.nouns(text)
        else:
            doc = nlp_en(text)
            word_list = [chunk.text for chunk in doc]

        resp = self.app_tool.success_result({
            "code": lang,
             "word_list": word_list,
            "hash": self.app_tool.get_str_hash(text)
        })

        return resp

    def detect_lang(self, text):
        lang = self.detect_text_lang(text)
        resp = self.app_tool.success_result({
            "code": lang,
            "hash": self.app_tool.get_str_hash(text)
        })

        return resp

    async def do_tokenizer(self, request):
        form = await request.post()
        resp = self.app_tool.fail_result("格式解析失败")
        if request.method == 'POST':
            text = None if 'text' not in form else form['text']
            sign = None if 'sign' not in form else form['sign']
            onlyDetectLang = None if 'onlyDetectLang' not in form else form['onlyDetectLang']
            try:
                is_vaild = self.app_tool.verify_post_sign(sign, text)
                is_self_ip = self.app_tool.is_self_ip(request)
                if is_vaild is False and is_self_ip is False:
                    return web.Response(text = json.dumps(self.app_tool.fail_result("sign检验失败")))
                
                text_json = self.app_tool.check_is_json(text)
                if text_json is False:
                    text_json = text

                if isinstance(text_json, str):
                    resp = self.detect_lang(text) if onlyDetectLang is not None else self.text_segment(text)
                elif isinstance(text_json, list):
                    ret_list = []
                    for text_data in text_json:
                        ret = self.detect_lang(text_data) if onlyDetectLang is not None else self.text_segment(text_data)
                        ret_list.append(ret)
                    resp = ret_list

                return web.Response(text=json.dumps(resp))
            except ValueError as e:
                return web.Response(text=json.dumps(resp))
        else:
            return web.Response(text=json.dumps(resp))

    def serve_multiple(self, app, workers):
        sock = socket()
        sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        sock.bind(('0.0.0.0', LISTEN_PORT))
        sock.set_inheritable(True)

        processes = []
        for i in range(workers):
            process = Process(target=web.run_app, name=f'worker-{i}', kwargs=dict(app=app, sock=sock))
            process.daemon = True
            process.start()
            processes.append(process)

        try:
            for process in processes:
                process.join()
        except KeyboardInterrupt:
            pass
        finally:
            for process in processes:
                process.terminate()
            sock.close()

    def main_multi(self, process_cnt):
        app = web.Application()
        app.router.add_get('/tokenizer', self.do_tokenizer, name="Tokenizer")
        app.router.add_post('/tokenizer', self.do_tokenizer, name="Tokenizer")

        cors = aiohttp_cors.setup(app, defaults={
            "*": aiohttp_cors.ResourceOptions(
                allow_credentials=True,
                expose_headers="*",
                allow_headers="*",
            )
        })
        self.serve_multiple(app, process_cnt)
    def main(self):
        app = web.Application()
        app.router.add_get('/tokenizer', self.do_tokenizer, name="tokenizer")
        app.router.add_post('/tokenizer', self.do_tokenizer, name="tokenizer")
        web.run_app(app, port=LISTEN_PORT)

if __name__ == '__main__':
    LISTEN_PORT = 8900
    process_cnt = 1
    AiPs = NLPServer()
    AiPs.main_multi(process_cnt)