# -*- coding: utf-8 -*-
"""Kiểm GHÉP NỐI: các module có tôn trọng giao_uoc.py không.

Khác `chay_test.py` ở chỗ: tệp kia chấm bot trả lời có ĐÚNG không, tệp này
chỉ hỏi các mảnh có LẮP VỪA nhau không.

Vì sao cần riêng một tệp: các module được viết song song, mỗi mảnh tự chạy
thì đều xanh, nhưng chữ ký lệch nhau một chữ là lúc ghép mới vỡ. Mà lúc đó
lỗi hiện ra ở chỗ khác hẳn nơi gây lỗi.

Chạy: python thu/kiem_ghep.py     (đứng ở thư mục chatbot)
Mã thoát 0 = mọi điều kiện đạt.
"""
import inspect
import io
import json
import os
import sys

GOC = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if GOC not in sys.path:
    sys.path.insert(0, GOC)

dat, truot, bo_qua = [], [], []


def kiem(nhan, ham):
    """Chạy một phép kiểm. Module chưa có thì BỎ QUA chứ không tính trượt —
    để bộ kiểm này dùng được ngay từ lúc mới có vài mảnh."""
    try:
        ket = ham()
    except ImportError as e:
        bo_qua.append((nhan, str(e)))
        return
    except Exception as e:
        truot.append((nhan, '%s: %s' % (type(e).__name__, e)))
        return
    if ket is True or ket is None:
        dat.append(nhan)
    else:
        truot.append((nhan, str(ket)))


# ------------------------------------------------------------- giao ước
def _giao_uoc_con_nguyen():
    import giao_uoc as g
    can = ('Doan', 'KetQuaTim', 'LocTim', 'SanPham', 'GiaGoi', 'KeyCuaKhach',
           'NguCanh', 'TraLoi', 'SO_DOAN_MAC_DINH', 'SO_DOAN_TOI_DA',
           'GIU_LICH_SU', 'CAU_CHUYEN_NGUOI', 'CAU_KHAI_LA_MAY', 'SAN_PHAM')
    thieu = [t for t in can if not hasattr(g, t)]
    return True if not thieu else 'giao_uoc thiếu: %s' % ', '.join(thieu)


def _tran_doan_hop_ly():
    import giao_uoc as g
    if not (1 <= g.SO_DOAN_MAC_DINH <= g.SO_DOAN_TOI_DA <= 8):
        return 'SO_DOAN_MAC_DINH=%s SO_DOAN_TOI_DA=%s — trần phải <= 8' % (
            g.SO_DOAN_MAC_DINH, g.SO_DOAN_TOI_DA)
    return True


# --------------------------------------------------------------- chữ ký
def _chu_ky_tra_loi():
    from nao.tra_loi import tra_loi
    ts = list(inspect.signature(tra_loi).parameters)
    return True if ts[:2] == ['cau_hoi', 'ngu_canh'] else \
        'tra_loi() nhận %s, giao ước đòi (cau_hoi, ngu_canh)' % ts


def _chu_ky_tim():
    from tim.lai import lay_bo_tim
    ts = list(inspect.signature(lay_bo_tim().tim).parameters)
    return True if ts[:3] == ['cau_hoi', 'loc', 'so_luong'] else \
        'tim() nhận %s, giao ước đòi (cau_hoi, loc, so_luong)' % ts


def _chu_ky_phan_loai():
    from nao.dinh_tuyen import phan_loai
    ts = list(inspect.signature(phan_loai).parameters)
    return True if ts[:2] == ['cau_hoi', 'ngu_canh'] else \
        'phan_loai() nhận %s' % ts


def _nha_cung_cap_du_hai_ham():
    from llm.giao_dien import NhaCungCap
    thieu = [t for t in ('phan_loai', 'dien_giai') if not hasattr(NhaCungCap, t)]
    return True if not thieu else 'NhaCungCap thiếu: %s' % ', '.join(thieu)


# ------------------------------------------------- luật cứng của hệ thống
def _loi_khong_bao_gio_ro():
    """Mọi nhánh phải trả câu có chữ, kể cả khi thiếu chỉ mục và thiếu CSDL."""
    from nao.tra_loi import tra_loi
    from giao_uoc import NguCanh
    for cau in ('giá bao nhiêu', 'cho em xin giảm giá', 'key của tôi còn hạn không',
                'cài EA vào MT5 thế nào', 'xin chào', '', 'x' * 900):
        kq = tra_loi(cau, NguCanh(phien='kiem_ghep', ngon_ngu='vi'))
        if not getattr(kq, 'tra_loi', '').strip():
            return 'câu %r trả về chuỗi rỗng' % cau[:40]
    return True


def _cam_ket_khong_goi_mo_hinh():
    """Xin giảm giá / hứa hẹn phải chuyển người NGAY, không tốn một token nào."""
    from nao.tra_loi import tra_loi
    from giao_uoc import NguCanh
    for cau in ('cho em xin giảm giá', 'bên mình có hoàn tiền không'):
        kq = tra_loi(cau, NguCanh(phien='kiem_ghep', ngon_ngu='vi'))
        if kq.da_goi_llm:
            return 'câu %r đã gọi mô hình — nhánh cam_ket phải chuyển người ngay' % cau
        if not kq.chuyen_nguoi:
            return 'câu %r không đặt chuyen_nguoi=True' % cau
    return True


def _khach_la_khong_tra_duoc_key():
    """Luật riêng tư: chưa đăng nhập thì không ai tra được key của ai."""
    from congcu.licence import key_cua_khach
    for u in ('', 'khach', None):
        if key_cua_khach(u):
            return 'key_cua_khach(%r) trả về dữ liệu — phải rỗng' % u
    return True


def _bo_test_doc_duoc():
    p = os.path.join(GOC, 'thu', 'bo_test.json')
    d = json.load(io.open(p, encoding='utf-8'))['cau_hoi']
    thieu = [m for m in d if 'hoi' not in m]
    return True if not thieu else '%d mục thiếu khoá "hoi"' % len(thieu)


def main():
    kiem('giao_uoc còn đủ tên', _giao_uoc_con_nguyen)
    kiem('trần số đoạn <= 8', _tran_doan_hop_ly)
    kiem('bộ test đọc được', _bo_test_doc_duoc)
    kiem('chữ ký tra_loi()', _chu_ky_tra_loi)
    kiem('chữ ký tim()', _chu_ky_tim)
    kiem('chữ ký phan_loai()', _chu_ky_phan_loai)
    kiem('NhaCungCap đủ hai hàm', _nha_cung_cap_du_hai_ham)
    kiem('không nhánh nào trả rỗng', _loi_khong_bao_gio_ro)
    kiem('cam_ket không gọi mô hình', _cam_ket_khong_goi_mo_hinh)
    kiem('khách lạ không tra được key', _khach_la_khong_tra_duoc_key)

    print('')
    for n in dat:
        print('  DAT     %s' % n)
    for n, ly_do in bo_qua:
        print('  BO QUA  %-34s (%s)' % (n, ly_do[:60]))
    for n, ly_do in truot:
        print('  TRUOT   %-34s %s' % (n, ly_do[:90]))
    print('')
    print('%d dat, %d truot, %d bo qua' % (len(dat), len(truot), len(bo_qua)))
    return 1 if truot else 0


if __name__ == '__main__':
    sys.exit(main())
