# -*- coding: utf-8 -*-
"""SINH_KIENTRUC.PY — dung lai architecture.md TU MA NGUON. Chay lai duoc.

VI SAO CAN TEP NAY
------------------
Ban architecture.md chep tay ngay 19/06/2026 da lech het moi con so khi doi
chieu voi ma ngay 23/09/2026:
    ghi dcav118, 331 dong   -> that la dcav119, 336 dong
    ghi CORE 14 module      -> that la 22, va da tach 3 thu muc con
    ghi RISK 3 module       -> that la 6
    ghi CONFIG 6 module     -> that la 9
So do mermaid ve theo nhung con so do nen cung sai theo.

Tai lieu kien truc chep tay luon tut lai sau ma. Sinh ra thi khong lech duoc.

Chay:  python sinh_kientruc.py [thu_muc_ea] [tep_ra.md]
"""
import io, os, re, sys
from datetime import date

GOC = sys.argv[1] if len(sys.argv) > 1 else '.'
RA = sys.argv[2] if len(sys.argv) > 2 else 'architecture.md'

# Ho bo loc — gom 35 filter lai cho so do doc duoc, thay vi ve 35 o vuong.
HO_FILTER = (
    ('Dao dong', ('Stoch', 'RSI', 'CCI', 'WilliamsR', 'MFI', 'DeMarker',
                  'UltimateOsc', 'RCI', 'RVI')),
    ('Xu huong', ('ADX', 'DMI', 'Aroon', 'Choppiness', 'MACDHist',
                  'ParabolicSAR', 'Supertrend', 'ElderPower', 'VIDYA', 'Ichimoku')),
    ('Bien dong', ('ATR', 'BollingerB', 'ADR', 'Squeeze')),
    ('Kenh gia', ('BBChannel', 'KeltnerChannel', 'DonchianChannel')),
    ('Khac', ('OBV', 'Pivot', 'RangePosition')),
)

TEN_NHOM = {
    'config': 'CONFIG — tham so dau vao',
    'core': 'CORE — vong doi va dieu phoi',
    'core/grid': 'CORE/GRID — luoi DCA',
    'core/orders': 'CORE/ORDERS — vao ra lenh',
    'core/tp_sl': 'CORE/TP_SL — chot loi cat lo',
    'data': 'DATA — trang thai chuoi lenh',
    'filters': 'FILTERS — bo loc tin hieu',
    'risk': 'RISK — quan tri rui ro',
    'services': 'SERVICES — ra ngoai may',
    'ui': 'UI — panel tren chart',
    'utils': 'UTILS — tien ich',
    'virtual': 'VIRTUAL — may ao',
}


def doc(p):
    for bm in ('utf-8', 'utf-8-sig', 'cp1258', 'latin-1'):
        try:
            return io.open(p, encoding=bm).read()
        except (UnicodeDecodeError, LookupError):
            continue
    return ''


def tep_chinh():
    for t in sorted(os.listdir(GOC)):
        if t.endswith('.mq5'):
            return t
    return None


def quet_cay():
    cay = {}
    for thu, _, teps in os.walk(os.path.join(GOC, 'include')):
        ds = sorted(t for t in teps if t.endswith('.mqh'))
        if not ds:
            continue
        nhom = os.path.relpath(thu, os.path.join(GOC, 'include')).replace(os.sep, '/')
        cay[nhom] = [(t, len(doc(os.path.join(thu, t)).splitlines())) for t in ds]
    return cay


def diem_vao(s):
    """Cac ham MT5 goi vao EA — vong doi that, doc tu ma."""
    ra = []
    for ten in ('OnInit', 'OnTick', 'OnTradeTransaction', 'OnChartEvent',
                'OnDeinit', 'OnTimer', 'OnTester'):
        if re.search(r'^\s*\w[\w\s\*]*\b' + ten + r'\s*\(', s, re.M):
            ra.append(ten)
    return ra


def thu_tu_include(s):
    return re.findall(r'^#include\s+"include[\\/](.+?)"', s, re.M)


def main():
    chinh = tep_chinh()
    if not chinh:
        print('KHONG THAY tep .mq5 nao trong', GOC)
        return 1
    s_chinh = doc(os.path.join(GOC, chinh))
    cay = quet_cay()
    tong = sum(len(v) for v in cay.values())
    tong_dong = sum(d for v in cay.values() for _, d in v)
    dv = diem_vao(s_chinh)
    inc = thu_tu_include(s_chinh)

    r = []
    r.append('# SMART DCA EA — Kiến trúc')
    r.append('')
    r.append('> **Tệp này SINH TỰ ĐỘNG từ mã nguồn** bằng `sinh_kientruc.py`, ngày %s.'
             % date.today().isoformat())
    r.append('> Đừng sửa tay — lần sinh sau sẽ đè lên.')
    r.append('')
    r.append('| | |')
    r.append('|---|---|')
    r.append('| Tệp chính | `%s` — %d dòng, thuần điều phối |'
             % (chinh, len(s_chinh.splitlines())))
    r.append('| Module | **%d** tệp `.mqh` · %s dòng |' % (tong, format(tong_dong, ',')))
    r.append('| Nhóm | %d thư mục |' % len(cay))
    r.append('| Điểm vào MT5 | %s |' % ' · '.join('`%s`' % x for x in dv))
    r.append('')
    r.append('---')
    r.append('')

    # ---- so do ----
    r.append('## Sơ đồ khối')
    r.append('')
    r.append('```mermaid')
    r.append('flowchart TB')
    r.append('    subgraph MT5["MetaTrader 5 gọi vào"]')
    for x in dv:
        r.append('        %s["%s()"]' % (x, x))
    r.append('    end')
    r.append('')
    for nhom in sorted(cay):
        ten = TEN_NHOM.get(nhom, nhom.upper())
        ma_nhom = 'G_' + re.sub(r'\W', '_', nhom)
        r.append('    subgraph %s["%s — %d module"]' % (ma_nhom, ten, len(cay[nhom])))
        if nhom == 'filters':
            for ho, ds in HO_FILTER:
                r.append('        F_%s["%s (%d)"]' % (re.sub(r'\W', '', ho), ho, len(ds)))
            r.append('        F_dieu_phoi["Dieu phoi: IndicatorFilters · KillChannel<br/>FilterAutoSwitch · BreakoutAdjust"]')
        else:
            for t, _ in cay[nhom]:
                ten_ngan = t.replace('DCA_', '').replace('.mqh', '')
                r.append('        %s["%s"]' % (re.sub(r'\W', '_', nhom + '_' + ten_ngan), ten_ngan))
        r.append('    end')
        r.append('')
    r.append('    MT5 --> G_core')
    r.append('    G_core --> G_core_grid')
    r.append('    G_core --> G_core_orders')
    r.append('    G_core --> G_core_tp_sl')
    r.append('    G_core --> G_filters')
    r.append('    G_core --> G_risk')
    r.append('    G_config --> G_core')
    r.append('    G_services --> G_config')
    r.append('    G_core --> G_data')
    r.append('    G_core --> G_ui')
    r.append('```')
    r.append('')

    # ---- bang nhom ----
    r.append('## Các nhóm module')
    r.append('')
    r.append('| Nhóm | Module | Dòng | Nội dung |')
    r.append('|---|---:|---:|---|')
    for nhom in sorted(cay, key=lambda x: -sum(d for _, d in cay[x])):
        d = sum(x for _, x in cay[nhom])
        ten_ds = ', '.join(t.replace('DCA_', '').replace('.mqh', '') for t, _ in cay[nhom][:5])
        if len(cay[nhom]) > 5:
            ten_ds += ', …'
        r.append('| `include/%s` | %d | %s | %s |' % (nhom, len(cay[nhom]), format(d, ','), ten_ds))
    r.append('')

    # ---- thu tu include ----
    r.append('## Thứ tự include trong `%s`' % chinh)
    r.append('')
    r.append('Thứ tự này **có ý nghĩa** — module sau dùng khai báo của module trước.')
    r.append('Đổi thứ tự là vỡ biên dịch.')
    r.append('')
    r.append('```')
    for i, x in enumerate(inc, 1):
        r.append('%3d  %s' % (i, x.replace('\\', '/')))
    r.append('```')
    r.append('')
    r.append('*(%d dòng include)*' % len(inc))
    r.append('')

    io.open(os.path.join(GOC, RA) if not os.path.isabs(RA) else RA,
            'w', encoding='utf-8', newline='\n').write('\n'.join(r) + '\n')
    print('SINH XONG -> %s' % RA)
    print('  tệp chính %s · %d dòng' % (chinh, len(s_chinh.splitlines())))
    print('  %d module · %s dòng · %d nhóm' % (tong, format(tong_dong, ','), len(cay)))
    print('  điểm vào: %s' % ', '.join(dv))
    print('  %d dòng include' % len(inc))
    return 0


if __name__ == '__main__':
    sys.exit(main())
