# -*- coding: utf-8 -*-
r"""B107: đóng gói BỘ APP liên quan MÀU và QUY TRÌNH (HLQT · CALIB · Agent-Lab · tra cứu CSDL) + README + zip."""
import hashlib, os, shutil, zipfile

GOC = r'C:\Claw 2\_BO_APP_MAU_QUYTRINH_20261014'
BO = os.path.join(GOC, 'BO_APP_MAU_VA_QUY_TRINH')
ZIP = os.path.join(GOC, 'BO_APP_MAU_VA_QUY_TRINH_20261014.zip')

APP = {
    'hlqt': (r'C:\Claw 2\Nghien cuu\Du-an-A-Quy-trinh-son\HLQT-app',
             ['server_hlqt.py', 'worker_hlqt.py', 'Chay_HLQT.bat', 'HDSD_HLQT.md', 'goi_kien_thuc_hlqt.py',
              'kien_thuc', '_tools']),
    'calib': (r'C:\Claw 2\Nghien cuu\Du-an-B-He-mau-Stain-Glaze\calib-app',
              ['server_calib.py', 'worker_calib.py', 'Chay_Calib.bat', 'HDSD_CALIB.md', '_tools']),
    'lab': (r'C:\Claw 2\Nghien cuu\Agent-Lab',
            ['server_lab.py', 'worker_lab.py', 'Chay_Agent-Lab.bat', 'HDSD_AGENT_LAB.md', 'dung_goi_kien_thuc.py',
             'kien_thuc', '_tools']),
    'tracuu': (r'C:\c\deepseek-harness\claw2-db', ['server_tra_cuu.py', 'nap_du_lieu.py']),
}
DATA = [(r'C:\Claw 2\Nghien cuu\Du-an-A-Quy-trinh-son\CSDLA.db', 'CSDLA.db'),
        (r'C:\Claw 2\Nghien cuu\Du-an-B-He-mau-Stain-Glaze\CSDLB.db', 'CSDLB.db'),
        (r'C:\Claw 2\Nghien cuu\Agent-Lab\lab.db', 'lab.db'),
        (r'C:\c\deepseek-harness\claw2-db\btchem.db', 'btchem.db')]
BO_QUA = ('__pycache__', 'viec', '_backup', '_server_log.txt', '_worker_log.txt', '_log_server.txt',
          'mat_khau.txt', 'bi_mat.txt', 'pass_hlqt.txt', 'pass_hieu_chinh.txt', 'email_bao.txt', '_nhip.json')

if os.path.isdir(GOC):
    shutil.rmtree(GOC)
os.makedirs(os.path.join(BO, 'apps'), exist_ok=True)
os.makedirs(os.path.join(BO, 'data'), exist_ok=True)

def chep(src, dich):
    if os.path.isdir(src):
        os.makedirs(dich, exist_ok=True)
        for t in sorted(os.listdir(src)):
            if t in BO_QUA:
                continue
            chep(os.path.join(src, t), os.path.join(dich, t))
    else:
        shutil.copy2(src, dich)

n = 0
for ten, (goc, muc) in APP.items():
    dich = os.path.join(BO, 'apps', ten)
    os.makedirs(dich, exist_ok=True)
    for m in muc:
        p = os.path.join(goc, m)
        if os.path.exists(p):
            chep(p, os.path.join(dich, m))
            n += 1
        else:
            print('   ⚠️ thiếu %s/%s' % (ten, m))
for src, ten in DATA:
    if os.path.exists(src):
        shutil.copy2(src, os.path.join(BO, 'data', ten))
        n += 1
    else:
        print('   ⚠️ thiếu data %s' % ten)

README = """# BỘ APP NỘI BỘ LIÊN QUAN **MÀU** VÀ **QUY TRÌNH** — BT-Chem
**Ngày đóng gói:** 14/10/2026 · **Đóng gói từ:** máy chạy thật (file đang phục vụ), đã loại `__pycache__`, log, thư mục việc, **và các file mật khẩu**.

## 1. Bốn app trong bộ

| # | App | Cổng | Chạy web nội bộ | Làm gì |
|---|-----|-----:|-----------------|--------|
| 1 | **HLQT** (`apps/hlqt`) | 8100 | `http://127.0.0.1:8100` · Tailscale `/hlqt/` | Huấn luyện quy trình sơn: 1 bản màu → **1 quy trình ĐỀ NGHỊ** (AGY đọc ảnh + áp CSDL A/B/D) → người dùng nhập **quy trình THẬT** → ghi vào **CSDL A**. Mỗi bước xong tự gửi email báo. |
| 2 | **CALIB** (`apps/calib`) | 8099 | `http://127.0.0.1:8099` · Tailscale `/calib/` | Hiệu chỉnh **màu** (CSDL B – hệ metal complex): nhập % màu pha trong base theo quy ước (cùng thông số thước kéo, cùng base, giấy trắng cùng loại) → bảng hiệu chỉnh + ghi CSDL B. |
| 3 | **Agent-Lab** (`apps/lab`) | 8098 | `http://127.0.0.1:8098` · Tailscale `/lab/` | Ảnh + yêu cầu → **2 bước AGY** (phân tích gỗ mộc/màu → lên **quy trình + công thức pha màu** theo CSDL A/B/C/D) → xuất **DOCX** + gửi email. Chỉ **ĐỀ NGHỊ**. |
| 4 | **Tra cứu CSDL** (`apps/tracuu`) | 8095 | `http://127.0.0.1:8095` · Tailscale `/csdl` | Tra cứu nhanh **CSDL nhà máy** (`btchem.db`: sự cố KPH, báo cáo SX/KT/CSKH/mẫu làm, mua hàng) và nạp dữ liệu (`nap_du_lieu.py`). |

Liên kết công khai (Tailscale Funnel): `https://desktop-9gsdkd2.tail0ffe94.ts.net` + `/hlqt/` · `/calib/` · `/lab/` · `/csdl` (nhớ **dấu `/` cuối** với các app).

## 2. Cách chạy từng app (Windows)
```
apps\\hlqt\\Chay_HLQT.bat        # cổng 8100
apps\\calib\\Chay_Calib.bat       # cổng 8099
apps\\lab\\Chay_Agent-Lab.bat     # cổng 8098
# tra cứu CSDL: python apps\\tracuu\\server_tra_cuu.py   (cổng 8095)
```
Mỗi app cần Python 3.11 + các gói trong `requirements` (xem HDSD từng app: `HDSD_HLQT.md`, `HDSD_CALIB.md`, `HDSD_AGENT_LAB.md`) và **cần AGY CLI** (`agy.exe`) cho các bước dùng AI mạnh.

## 3. Dữ liệu kèm theo (`data/`)
- `CSDLA.db` — **CSDL A**: quy trình sơn (HLQT ghi vào)
- `CSDLB.db` — **CSDL B**: hệ màu metal complex + bảng in (CALIB dùng)
- `lab.db` — hàng đợi/việc của Agent-Lab
- `btchem.db` — CSDL nhà máy (app tra cứu CSDL dùng)

## 4. Bảo mật — ĐỌC TRƯỚC KHI CHUYỂN BỘ NÀY CHO NGƯỜI KHÁC
- Bộ này **KHÔNG chứa file mật khẩu** (`mat_khau.txt`, `pass_hlqt.txt`, `pass_hieu_chinh.txt`, `bi_mat.txt`). Khi triển khai, tạo lại các file đó trong thư mục app với **mật khẩu do người quản trị đặt** (cùng tên file, xem HDSD).
- CSDL trong `data/` là **dữ liệu thật của Công ty** — không đưa ra ngoài.
- App chỉ nghe trên `127.0.0.1`; ra ngoài là qua **Tailscale Funnel** (có mật khẩu app).

## 5. Quy ước vận hành (đã cố định trong hệ)
- Kết quả từ app là **ĐỀ NGHỊ** — người dùng phải duyệt trước khi ghi CSDL thật.
- Ghi CSDL A/B đều **yêu cầu mật khẩu** và **backup trước khi ghi**.
- Mọi bước hoàn tất (đề nghị · đối chiếu · đã ghi) → **tự gửi email báo** cho người phụ trách.
"""
open(os.path.join(BO, 'README_BO_APP.md'), 'w', encoding='utf-8').write(README)

with zipfile.ZipFile(ZIP, 'w', zipfile.ZIP_DEFLATED) as z:
    for g, _, fs in os.walk(BO):
        for f in fs:
            p = os.path.join(g, f)
            z.write(p, os.path.relpath(p, GOC))
sha = hashlib.sha256(open(ZIP, 'rb').read()).hexdigest()
print('  đã tạo:', ZIP)
print('  kích thước: %d B (%.2f MB)' % (os.path.getsize(ZIP), os.path.getsize(ZIP) / 1048576))
print('  số tệp trong zip:', sum(len(fs) for _, _, fs in os.walk(BO)))
print('  sha256:', sha[:32], '...')
