# -*- coding: utf-8 -*-
"""SHOP — HỒ SƠ TỪNG SHOP: phần riêng tách khỏi lõi tư vấn dùng chung.

VÌ SAO (chủ dự án 24/09/2026)
-----------------------------
"Với mỗi hệ thống shop sẽ có một quy tắc ứng xử, khung nền, dữ liệu, và ráp
cái đó với các kênh". Một hệ thống chạy nhiều shop, mỗi shop là một
`khong_gian`. Ba lớp:

  1. HỒ SƠ SHOP (tệp này + shop/<ma>.py)
       - quy tắc ứng xử: vai, xưng hô, điều cấm, câu chào/chuyển người
       - khung nền: NGÀNH (shop/nganh/<nganh>.py — từ vựng chuyên môn, luật
         nhận diện ý định riêng) + các tính năng bật/tắt (tra key, đặt code...)
       - dữ liệu: tên miền, liên hệ, danh mục, thư mục tài liệu, tệp chỉ mục
  2. LÕI (nao/, llm/, congcu/, kho/, tim/) — không chứa gì riêng của shop nào;
     mọi chỗ cần thì gọi `lay(ngu_canh.khong_gian)`.
  3. KÊNH (kenh/, app.py) — nhận tin, gắn đúng khong_gian, gửi trả lời.

Thêm shop mới = thêm shop/<ma>.py (+ ngành nếu chưa có) rồi khai trong
_CAC_SHOP. Không sửa lõi.

Tự kiểm:  python thu/thu_shop.py
"""
from __future__ import annotations

import os
from dataclasses import dataclass, field
from typing import Any, Dict, FrozenSet, List, Optional, Tuple

MAC_DINH = 'tradingauto'


@dataclass(frozen=True)
class HoSoShop:
    # ---- nhận diện ----
    ma: str                                  # = khong_gian
    ten: str                                 # tên hiển thị: 'TradingAuto'
    nganh: str                               # gói ngành: 'trading' | 'spa'
    san_sang: bool = True                    # False: chưa nhận khách (đang phỏng vấn/soạn dữ liệu)

    # ---- quy tắc ứng xử ----
    vai: str = ''                            # đoạn VAI đầu câu dẫn tư vấn
    xung_ho: str = 'Xưng "em", gọi khách "anh/chị". Không tâng bốc, không rào đón.'
    ten_tai_lieu: str = ''                   # 'Tài liệu của TradingAuto'
    kien_thuc_nghe: str = ''                 # tầng 2: kiến thức chung của nghề được dùng tự do
    thong_tin_rieng: str = ''                # tầng 3: loại thông tin CHỈ nói khi có tài liệu
    bang_thuat_ngu: str = ''                 # bảng tra chuẩn đưa vào câu dẫn (vd mã lỗi MT4/MT5)
    dieu_cam_them: Tuple[str, ...] = ()      # điều cấm riêng của ngành/shop (thêm vào ĐIỀU CẤM chung)
    vai_ghi_chep: str = ''                   # vai trong prompt tóm gọn / tóm tắt phiên
    tu_gioi_thieu: Dict[str, str] = field(default_factory=dict)   # {'vi':..., 'en':...}
    goi_y_viec: Dict[str, str] = field(default_factory=dict)      # câu chào: bot giúp được gì
    vi_du: Dict[str, str] = field(default_factory=dict)           # ví dụ minh hoạ trong luật tư vấn (llm/giao_dien.py)

    # ---- dữ liệu ----
    ten_mien: str = ''                       # 'https://tradingauto.org' — đổi link nội bộ thành link đầy đủ
    trang_goc: FrozenSet[str] = frozenset()  # đoạn đầu đường dẫn là trang THẬT của web
    lien_he: Dict[str, str] = field(default_factory=dict)         # {'zalo':..., 'telegram':...}
    danh_muc_them: Tuple[str, ...] = ()      # sản phẩm/dịch vụ bán thật nhưng không có trong bảng danh mục
    # Giá gom một nhóm sản phẩm: {slug: (tên, (dòng giá, ...), dòng gọn cho bảng giá tổng)} — hoặc
    # {slug: hàm trả bộ đó / None} để đọc từ CSDL lúc dùng (TradingAuto: VipTrend từ bảng product).
    # Đi vào MỌI nhánh giá (bảng tổng, giá một sản phẩm) và danh mục gửi mô hình. Đọc qua gia_them().
    bang_gia_them: Dict[str, Any] = field(default_factory=dict)
    # Nút gợi ý của kênh chat (Messenger): {chữ của nút: id mục kho}. Khách bấm nút -> chữ tới trùng khít ->
    # trả nguyên văn mục đó, không gọi mô hình (nao/tra_loi.py::_tra_loi_nut_bam).
    nut_bam: Dict[str, int] = field(default_factory=dict)
    trang_bang_gia: str = ''                 # '/Pricing' — nơi mời khách xem giá (rỗng: hỏi để báo giá)
    dung_bang_product: bool = False          # danh mục + giá lấy từ bảng `product` (TradingAuto)
    thu_muc_site: Optional[str] = None       # thư mục trang web để dựng chỉ mục (None: chỉ kho tư vấn)

    # ---- khung nền: tính năng ----
    co_tra_key: bool = False                 # nhánh hỏi key/license
    co_dat_code: bool = False                # dịch vụ code theo yêu cầu (chủ đề 'code', vai chuyên gia)

    # ---- bài đăng Fanpage hằng ngày (kenh/bai_ngay.py) ----
    # {'lich': (nhóm thứ Hai, …, nhóm Chủ nhật), 'nguon': {nhóm: [nguồn, …] | 'kho'}, 'kho_bo': (id mục kho không
    #  dùng làm bài, …), 'luat': 'luật viết riêng của shop'}. Một nguồn: {'khoa', 'ten', 'link', 'trang' (tệp PHP
    #  dưới public/pages, lấy chữ hiển thị làm SỰ THẬT), 'them' (ghi chú cho người viết), 'anh' (URL https)}.
    # Rỗng: shop không bật bài hằng ngày.
    bai_ngay: Dict[str, Any] = field(default_factory=dict)

    def tep_chi_muc(self, thu_muc_goc: str) -> str:
        """Mỗi shop một tệp chỉ mục. TradingAuto giữ tên cũ chi_muc.sqlite để không phải dựng lại."""
        ten = 'chi_muc.sqlite' if self.ma == MAC_DINH else f'chi_muc_{self.ma}.sqlite'
        return os.path.join(thu_muc_goc, ten)


def _nap() -> Dict[str, HoSoShop]:
    from . import tradingauto, spa
    return {h.ma: h for h in (tradingauto.HO_SO, spa.HO_SO)}


_CAC_SHOP: Dict[str, HoSoShop] = _nap()


def lay(ma: Optional[str]) -> HoSoShop:
    """Hồ sơ của một khong_gian. Mã lạ (hoặc rỗng) -> shop mặc định, để lõi
    không bao giờ ngã vì một khong_gian gõ sai trong dữ liệu cũ."""
    return _CAC_SHOP.get((ma or '').strip()) or _CAC_SHOP[MAC_DINH]


def co(ma: Optional[str]) -> bool:
    """Mã này có phải một shop đã khai VÀ đang nhận khách không (cổng web/kênh dùng để chặn mã lạ)."""
    h = _CAC_SHOP.get((ma or '').strip())
    return bool(h and h.san_sang)


def ds_shop(chi_san_sang: bool = False) -> List[HoSoShop]:
    return [h for h in _CAC_SHOP.values() if h.san_sang or not chi_san_sang]




def gia_them(hs: HoSoShop) -> Dict[str, Tuple[str, Tuple[str, ...], str]]:
    """bang_gia_them đã giải: giá trị là hàm thì gọi (đọc CSDL), trả None / lỗi thì bỏ nhóm đó."""
    ra = {}
    for slug, gt in (hs.bang_gia_them or {}).items():
        try:
            gt = gt() if callable(gt) else gt
        except Exception:  # noqa: BLE001 - thiếu một nhóm giá còn hơn bot sập
            gt = None
        if gt:
            ra[slug] = gt
    return ra
