# -*- coding: utf-8 -*-
"""CAU_HINH.PY — đọc cấu hình môi trường và dựng nhà cung cấp AI đang dùng.

VÌ SAO tệp này tồn tại riêng: cổng (`app.py`) và lõi (`nao/`) không được
biết .env nằm ở đâu hay nhà cung cấp nào đang bật — theo giao_uoc.py mục 1,
"đổi nhà cung cấp phải là sửa MỘT file, không phải sửa lõi". Tệp này chính
là "một file" đó.

VÌ SAO đọc .env bằng tay thay vì python-dotenv: chỉ vài dòng KHOA=gia_tri,
thêm một thư viện ngoài cho việc này là phí — và VPS triển khai (đường dẫn
thứ hai bên dưới) có thể chưa cài dotenv. congcu/san_pham.py và
congcu/licence.py cũng tự đọc .env kiểu này, ở đây lặp lại đúng cách làm đó
cho nhất quán (dù không dùng chung hàm, vì mỗi tệp cố tình độc lập — xem
"CÁC MODULE KHÁC ĐANG ĐƯỢC VIẾT SONG SONG" trong đề bài: không chắc tệp kia
đã tồn tại lúc tệp này chạy).
"""
from __future__ import annotations

import logging
import os
from pathlib import Path
from typing import Dict, Optional

logger = logging.getLogger('chatbot.cau_hinh')


# =====================================================================
# ĐỌC .env — máy dev Windows trước, VPS thật sau
# =====================================================================

# Suy tu vi tri CUA CHINH TEP NAY, khong viet cung o dia.
# Bo cuc: <goc>/private/services/chatbot/cau_hinh.py
#   -> len 3 bac la <goc>/private
# Viet cung 'G:/Xampp/htdocs' thi chay tren may chu Linux la chet ngay,
# ma thong bao loi ('unable to open database file') khong he nhac gi toi
# duong dan — da mat mot luot deploy vi dung cai nay.
_PRIVATE = Path(__file__).resolve().parent.parent.parent

DUONG_DAN_ENV_UNG_VIEN = (
    _PRIVATE / '.env',
    Path('/home/admin/web/tradingauto.org/private/.env'),
    Path('G:/Xampp/htdocs/private/.env'),
)


def _doc_tep_env(duong_dan: Path) -> Dict[str, str]:
    """Đọc thô một tệp .env dạng KHOA=gia_tri, bỏ qua dòng trống/chú thích.
    Không hiểu biến lồng nhau hay export — cú pháp .env ở dự án này đơn
    giản, không cần bộ phân tích đầy đủ."""
    ket_qua: Dict[str, str] = {}
    try:
        noi_dung = duong_dan.read_text(encoding='utf-8')
    except OSError:
        return ket_qua
    for dong in noi_dung.splitlines():
        dong = dong.strip()
        if not dong or dong.startswith('#') or '=' not in dong:
            continue
        khoa, _, gia_tri = dong.partition('=')
        khoa = khoa.strip()
        if khoa:
            ket_qua[khoa] = gia_tri.strip().strip('"').strip("'")
    return ket_qua


def _doc_tep_env_dau_tien_co() -> Dict[str, str]:
    for duong_dan in DUONG_DAN_ENV_UNG_VIEN:
        tep = _doc_tep_env(duong_dan)
        if tep:
            return tep
    return {}


# Đọc MỘT LẦN lúc nạp module — .env không đổi trong lúc tiến trình sống,
# đổi cấu hình thì phải khởi động lại tiến trình (giống mọi cấu hình khác
# của cổng này, xem app.py).
_BIEN_TU_TEP: Dict[str, str] = _doc_tep_env_dau_tien_co()


def lay(khoa: str, mac_dinh: str = '') -> str:
    """Biến môi trường thật ĐÈ LÊN giá trị đọc từ .env — máy chủ thật
    thường set biến môi trường trực tiếp (an toàn hơn tệp), giống hệt quy
    tắc trong congcu/san_pham.py và congcu/licence.py."""
    if khoa in os.environ and os.environ[khoa] != '':
        return os.environ[khoa]
    return _BIEN_TU_TEP.get(khoa, mac_dinh)


# =====================================================================
# CÁC KHOÁ CẤU HÌNH CỦA CỔNG CHATBOT
# =====================================================================

def cong() -> int:
    """Cổng TCP lắng nghe — mặc định 8787, khớp CHAT_URL mặc định bên PHP
    (private/app/lib/chat_config.php)."""
    try:
        return int(lay('CHATBOT_CONG', '8787'))
    except ValueError:
        logger.error(
            "CHATBOT_CONG không phải số nguyên hợp lệ (%r) — dùng mặc định 8787.",
            lay('CHATBOT_CONG'),
        )
        return 8787


def khoa_noi_bo() -> str:
    """Khoá riêng giữa PHP và cổng Python — khớp CHAT_KHOA bên PHP. Rỗng
    nghĩa là KHÔNG kiểm tra header (đúng khi cổng và web cùng chạy trên
    127.0.0.1, không lộ ra Internet)."""
    return lay('CHATBOT_KHOA_NOI_BO', '')


def ten_nha_cung_cap() -> str:
    return lay('CHATBOT_NHA_CUNG_CAP', 'rong').strip().lower()


def thu_muc_log() -> Path:
    """Mặc định private/logs/chat — CÙNG thư mục PHP đã dùng cho
    CHAT_THU_MUC_LOG (xem private/app/lib/chat_config.php), vì hai bên ghi
    hai loại tệp bổ sung cho nhau (web-*.jsonl của PHP, còn cổng Python ghi
    phần hội thoại đầy đủ), không phải hai kho tách biệt."""
    gia_tri = lay('CHATBOT_THU_MUC_LOG', '')
    if gia_tri:
        return Path(gia_tri)
    # Suy ra private/ từ vị trí tệp này: cau_hinh.py nằm ngay trong
    # private/services/chatbot/, nên cha của cha là private/.
    thu_muc_chatbot = Path(__file__).resolve().parent
    thu_muc_private = thu_muc_chatbot.parent.parent
    return thu_muc_private / 'logs' / 'chat'


# =====================================================================
# DỰNG NHÀ CUNG CẤP AI — hỏng thì RƠI VỀ NhaCungCapRong, không bao giờ 500
# =====================================================================

def _nap_nha_cung_cap_rong():
    """Nạp NhaCungCapRong — điểm rơi cuối cùng. Nếu ngay cả bước này cũng
    lỗi thì hệ thực sự không còn gì để dùng (lỗi cấu trúc thư mục nghiêm
    trọng), lúc đó mới cho phép ném lỗi ra ngoài."""
    try:
        from llm.rong import NhaCungCapRong
    except ImportError:
        import sys
        sys.path.insert(0, str(Path(__file__).resolve().parent))
        from llm.rong import NhaCungCapRong  # type: ignore
    return NhaCungCapRong()


def lay_nha_cung_cap():
    """Dựng đúng nhà cung cấp AI theo CHATBOT_NHA_CUNG_CAP.

    VÌ SAO luôn phải trả về được một đối tượng dùng được: bot phải luôn
    trả lời được điều gì đó (xem đề bài) — thiếu file llm/anthropic.py
    (đang viết song song), thiếu khoá API, hay gõ sai tên trong .env đều
    KHÔNG được làm cổng sập lúc khởi động. Mọi nhánh lỗi ở đây đều ghi
    logging.error tiếng Việt rồi rơi về NhaCungCapRong.
    """
    ten = ten_nha_cung_cap()

    if ten == 'anthropic':
        try:
            from llm.anthropic import NhaCungCapAnthropic
            return NhaCungCapAnthropic()
        except Exception as loi:  # noqa: BLE001 - phải sống sót dù lỗi gì
            logger.error(
                "Không dựng được NhaCungCapAnthropic (CHATBOT_NHA_CUNG_CAP=anthropic): "
                "%s — rơi về NhaCungCapRong để bot vẫn trả lời được.", loi,
            )
            return _nap_nha_cung_cap_rong()

    if ten == 'openai':
        try:
            from llm.tuongthich_openai import NhaCungCapTuongThichOpenAI
            return NhaCungCapTuongThichOpenAI()
        except Exception as loi:  # noqa: BLE001
            logger.error(
                "Không dựng được NhaCungCapTuongThichOpenAI (CHATBOT_NHA_CUNG_CAP=openai): "
                "%s — rơi về NhaCungCapRong để bot vẫn trả lời được.", loi,
            )
            return _nap_nha_cung_cap_rong()

    if ten != 'rong':
        logger.error(
            "CHATBOT_NHA_CUNG_CAP=%r không phải giá trị hợp lệ ('rong'|'anthropic'|"
            "'openai') — dùng NhaCungCapRong.", ten,
        )

    try:
        return _nap_nha_cung_cap_rong()
    except Exception as loi:  # noqa: BLE001 - điểm rơi cuối cùng
        logger.critical(
            "Không nạp nổi cả NhaCungCapRong — cấu trúc thư mục services/chatbot "
            "có vấn đề nghiêm trọng: %s", loi,
        )
        raise


if __name__ == '__main__':
    # ---- Tự kiểm nhanh, không cần .env thật ----
    logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')

    print('=== Tự kiểm cau_hinh.py ===')
    print('cong() =', cong())
    print('khoa_noi_bo() =', repr(khoa_noi_bo()))
    print('ten_nha_cung_cap() =', ten_nha_cung_cap())
    print('thu_muc_log() =', thu_muc_log())

    print('\n--- lay_nha_cung_cap() với cấu hình mặc định (rong) ---')
    ncc = lay_nha_cung_cap()
    print('Đối tượng:', ncc.__class__.__name__, '- ten =', getattr(ncc, 'ten', '?'))

    print('\n--- Ép CHATBOT_NHA_CUNG_CAP=anthropic mà KHÔNG có ANTHROPIC_API_KEY ---')
    os.environ['CHATBOT_NHA_CUNG_CAP'] = 'anthropic'
    os.environ.pop('ANTHROPIC_API_KEY', None)
    ncc2 = lay_nha_cung_cap()
    print('Đối tượng:', ncc2.__class__.__name__, '- ten =', getattr(ncc2, 'ten', '?'))
    assert ncc2.__class__.__name__ == 'NhaCungCapRong', 'LỖI: phải rơi về NhaCungCapRong khi thiếu khoá'
    print('OK: rơi về NhaCungCapRong đúng như kỳ vọng, bot vẫn sống.')
    del os.environ['CHATBOT_NHA_CUNG_CAP']
