import os
import json
import sys
from dotenv import load_dotenv

# 載入 .env 環境變數
load_dotenv()

# 基本路徑設定
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(BASE_DIR, 'data')
LOG_DIR = os.path.join(BASE_DIR, 'logs')
UPLOAD_FOLDER = os.path.join(BASE_DIR, 'web/static/uploads')

# 建立必要目錄
for d in [DATA_DIR, LOG_DIR, UPLOAD_FOLDER]:
    os.makedirs(d, exist_ok=True)

# ==========================================
# 資料庫設定
# ==========================================
# 支援 SQLite 和 PostgreSQL 兩種資料庫
# 預設使用 SQLite (本地開發)，可透過環境變數切換到 PostgreSQL
USE_POSTGRESQL = os.getenv('USE_POSTGRESQL', 'false').lower() == 'true'

if USE_POSTGRESQL:
    # PostgreSQL 連線設定
    POSTGRES_HOST = os.getenv('POSTGRES_HOST', 'momo-postgres')
    POSTGRES_PORT = os.getenv('POSTGRES_PORT', '5432')
    POSTGRES_USER = os.getenv('POSTGRES_USER', 'momo')
    POSTGRES_PASSWORD = os.getenv('POSTGRES_PASSWORD')
    POSTGRES_DB = os.getenv('POSTGRES_DB', 'momo_analytics')

    # 檢查密碼是否設置
    if not POSTGRES_PASSWORD:
        raise ValueError(
            f"❌ 資料庫密碼未設置！請檢查：\n"
            f"1. .env 檔案中是否設置了 POSTGRES_PASSWORD\n"
            f"2. Docker Compose 環境變數是否正確傳遞\n"
            f"3. 容器重啟後環境變數是否生效\n"
            f"當前環境變數：USE_POSTGRESQL=true, POSTGRES_HOST={POSTGRES_HOST}, POSTGRES_USER={POSTGRES_USER}"
        )

    DATABASE_PATH = f"postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}:{POSTGRES_PORT}/{POSTGRES_DB}"
    DATABASE_TYPE = 'postgresql'
else:
    # SQLite 連線設定 (開發環境或備用)
    DATABASE_PATH = f"sqlite:///{os.path.join(DATA_DIR, 'momo_database.db')}"
    DATABASE_TYPE = 'sqlite'

# ==========================================
# 安全設定（從環境變數讀取）
# ==========================================
import sys as _sys


def _is_test_context() -> bool:
    return (
        os.getenv("PYTEST_CURRENT_TEST") is not None
        or "pytest" in sys.modules
        or os.getenv("MOMO_ALLOW_INSECURE_CONFIG_FOR_TESTS", "").lower() == "true"
    )


def _require_env(var_name: str, *, insecure_values: tuple[str, ...] = ()) -> str:
    value = os.getenv(var_name)
    if value and value not in insecure_values:
        return value

    if _is_test_context():
        fallback = f"test-{var_name.lower()}"
        print(f"[WARN] {var_name} 未設定，測試環境使用暫時值。", file=_sys.stderr)
        return fallback

    if var_name == "LOGIN_PASSWORD":
        print("[FATAL] LOGIN_PASSWORD 環境變數未設定，拒絕啟動。請在 .env 或 Docker 環境設定此值。", file=_sys.stderr)
    else:
        print(f"[FATAL] {var_name} 環境變數未設定或仍為不安全預設值，拒絕啟動。請改用安全值。", file=_sys.stderr)
    _sys.exit(1)


LOGIN_PASSWORD = _require_env("LOGIN_PASSWORD")
SECRET_KEY = _require_env("SECRET_KEY", insecure_values=('your_flask_secret_key', 'change_me', ''))

# ==========================================
# 通訊模組設定（從環境變數讀取）
# ==========================================

# --- Telegram Bot ---
TELEGRAM_BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN', '')
try:
    TELEGRAM_CHAT_IDS = json.loads(os.getenv('TELEGRAM_CHAT_IDS', '[]'))
except json.JSONDecodeError:
    TELEGRAM_CHAT_IDS = []

# --- Line Notify ---
LINE_ENABLED = os.getenv('LINE_ENABLED', 'false').lower() == 'true'  # 預設關閉
LINE_CHANNEL_ACCESS_TOKEN = os.getenv('LINE_CHANNEL_ACCESS_TOKEN', '')
LINE_GROUP_ID = os.getenv('LINE_GROUP_ID', '')

# --- Email (SMTP) ---
EMAIL_HOST = os.getenv('EMAIL_HOST', 'smtp.gmail.com')
EMAIL_PORT = int(os.getenv('EMAIL_PORT', '587'))
EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER', '')
EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD', '')  # 注意：若使用 Gmail，需設定「應用程式密碼」
EMAIL_SENDER = os.getenv('EMAIL_SENDER', '')
EMAIL_RECEIVER = os.getenv('EMAIL_RECEIVER', '')

# ==========================================
# 網路設定（從環境變數讀取）
# ==========================================
PUBLIC_URL = os.getenv('PUBLIC_URL', 'https://mo.wooo.work')

# ==========================================
# 市場情報模組設定（預設全部關閉）
# ==========================================
MARKET_INTEL_ENABLED = os.getenv('MARKET_INTEL_ENABLED', 'false').lower() == 'true'
MARKET_INTEL_CRAWLER_ENABLED = os.getenv('MARKET_INTEL_CRAWLER_ENABLED', 'false').lower() == 'true'
MARKET_INTEL_WRITE_ENABLED = os.getenv('MARKET_INTEL_WRITE_ENABLED', 'false').lower() == 'true'

# 補上 EXCEL_EXPORT_DIR 定義
EXCEL_EXPORT_DIR = os.path.join(DATA_DIR, 'excel_exports')

# 更新建立目錄清單 (確保系統會自動建立這個資料夾)
for d in [DATA_DIR, LOG_DIR, UPLOAD_FOLDER, EXCEL_EXPORT_DIR]:
    os.makedirs(d, exist_ok=True)

# MOMO 分類清單 (從 JSON 檔案動態讀取)
def load_momo_categories():
    import json
    import time
    
    categories_path = os.path.join(DATA_DIR, 'categories.json')
    
    # 預設分類，用於首次啟動或檔案遺失時
    default_categories = [
        {"name": "保養超值組", "url": "https://www.momoshop.com.tw/category/DgrpCategory.jsp?d_code=1111700012"},
        {"name": "化妝水", "url": "https://www.momoshop.com.tw/category/DgrpCategory.jsp?d_code=1111700001"},
        {"name": "精華液", "url": "https://www.momoshop.com.tw/category/DgrpCategory.jsp?d_code=1111700002&p_orderType=4&showType=chessboardType"},
        {"name": "乳液", "url": "https://www.momoshop.com.tw/category/DgrpCategory.jsp?d_code=1111700003&p_orderType=4&showType=chessboardType"},
        {"name": "乳霜", "url": "https://www.momoshop.com.tw/category/DgrpCategory.jsp?d_code=1111700004&p_orderType=4&showType=chessboardType"},
        {"name": "凝膠", "url": "https://www.momoshop.com.tw/category/DgrpCategory.jsp?d_code=1111700005&p_orderType=4&showType=chessboardType"},
        {"name": "面膜", "url": "https://www.momoshop.com.tw/category/DgrpCategory.jsp?d_code=1111700006&p_orderType=4&showType=chessboardType"},
        {"name": "眼霜", "url": "https://www.momoshop.com.tw/category/DgrpCategory.jsp?d_code=1111700007&p_orderType=4&showType=chessboardType"},
        {"name": "護唇膏", "url": "https://www.momoshop.com.tw/category/DgrpCategory.jsp?d_code=1111700008&p_orderType=4&showType=chessboardType"},
        {"name": "防曬", "url": "https://www.momoshop.com.tw/category/DgrpCategory.jsp?d_code=1111700009&p_orderType=4&showType=chessboardType"},
        {"name": "素顏霜", "url": "https://www.momoshop.com.tw/category/DgrpCategory.jsp?d_code=1111700010&p_orderType=4&showType=chessboardType"},
        {"name": "美顏霜", "url": "https://www.momoshop.com.tw/category/DgrpCategory.jsp?d_code=1111700011&p_orderType=4&showType=chessboardType"},
        {"name": "身體護理", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=1100901499&sourcePageType=4"},
        {"name": "手部保養", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=1100901655&sourcePageType=4"},
        {"name": "足部保養", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=1100901656&sourcePageType=4"},
        {"name": "局部護理", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=1100901505&sourcePageType=4"},
        {"name": "止汗體香", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=1100901503&sourcePageType=4"},
        {"name": "嬰幼身體保養品牌旗艦", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=1100901724&sourcePageType=4"},
        {"name": "嬰幼本月主打", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=2705200081&sourcePageType=4"},
        {"name": "嬰幼清潔用品", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=2705200349&p_orderType=4&showType=chessboardType"},
        {"name": "嬰幼保養護膚", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=2705200350&p_orderType=4&showType=chessboardType"},
        {"name": "媽咪孕期保養", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=2705200352&p_orderType=4&showType=chessboardType"},
        {"name": "送禮超值組", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=2705200348&p_orderType=4&showType=chessboardType"},
        {"name": "嬰幼品牌總覽", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=2705200348&p_orderType=4&showType=chessboardType"},
        {"name": "私密保養本月主打", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=1105900060&sourcePageType=4"},
        {"name": "私密保養", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=1105900002&sourcePageType=4"},
        {"name": "私密清潔", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=1105900003&sourcePageType=4"},
        {"name": "除毛", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=1105900154&sourcePageType=4"},
        {"name": "私密保養推薦品牌", "url": "https://www.momoshop.com.tw/category/MgrpCategory.jsp?m_code=1105900023&sourcePageType=4"}
    ]

    if not os.path.exists(categories_path):
        # 如果檔案不存在，使用預設值並為每項加上 ID 後建立新檔案
        categories_with_id = []
        for i, cat in enumerate(default_categories):
            cat['id'] = int(time.time() * 1000) + i
            categories_with_id.append(cat)
        try:
            with open(categories_path, 'w', encoding='utf-8') as f:
                json.dump(categories_with_id, f, ensure_ascii=False, indent=4)
            return categories_with_id
        except Exception as e:
            print(f"Error creating categories.json: {e}")
            return default_categories
    
    try:
        # V-Fix: 檢查檔案大小，如果過大 (例如超過 1MB) 則視為異常，直接使用預設值，避免讀取卡死
        if os.path.exists(categories_path):
            try:
                if os.path.getsize(categories_path) > 1024 * 1024:
                    print(f"⚠️ Warning: categories.json is too large ({os.path.getsize(categories_path)} bytes). Using defaults.")
                    return default_categories
            except OSError:
                return default_categories

        with open(categories_path, 'r', encoding='utf-8') as f:
            try:
                content = f.read().strip()
            except Exception:
                return default_categories

            if not content:
                return default_categories
            
            data = json.loads(content)
            # 若讀取到的列表為空，則回傳預設值 (修正空檔案導致爬蟲不工作的問題)
            if not data:
                return default_categories
            return data
    except (json.JSONDecodeError, FileNotFoundError, OSError):
        # 如果檔案損毀或讀取失敗，回傳預設值
        return default_categories

MOMO_CATEGORIES = load_momo_categories()

# ==========================================
# 密碼安全設定
# ==========================================
PASSWORD_MIN_LENGTH = int(os.getenv('PASSWORD_MIN_LENGTH', '8'))
PASSWORD_REQUIRE_UPPERCASE = os.getenv('PASSWORD_REQUIRE_UPPERCASE', 'true').lower() == 'true'
PASSWORD_REQUIRE_LOWERCASE = os.getenv('PASSWORD_REQUIRE_LOWERCASE', 'true').lower() == 'true'
PASSWORD_REQUIRE_DIGIT = os.getenv('PASSWORD_REQUIRE_DIGIT', 'true').lower() == 'true'
PASSWORD_REQUIRE_SPECIAL = os.getenv('PASSWORD_REQUIRE_SPECIAL', 'false').lower() == 'true'
PASSWORD_SPECIAL_CHARS = os.getenv('PASSWORD_SPECIAL_CHARS', '!@#$%^&*()_+-=[]{}|;:,.<>?')
PASSWORD_EXPIRY_DAYS = int(os.getenv('PASSWORD_EXPIRY_DAYS', '90'))

# ==========================================
# 外部服務連結 (分析報表選單)
# ==========================================
METABASE_URL = os.getenv('METABASE_URL', '')  # Metabase BI 連結
GRIST_URL = os.getenv('GRIST_URL', '')  # Grist 資料協作連結

# ==========================================
# AI 服務設定
# ==========================================
# Hermes AI Service (競價情報分析)
# V-New (ADR-027 Phase 2)：所有 host 解析必須 lazy，禁止 import-time freeze。
# 理由：import 時 GCP 還沒探測（resolve_ollama_host 內部 cache 120s），
#       若 freeze 到 module attr，主機 GCP 後來掛掉、cache 失效仍取不到新值。
def get_hermes_url():
    """Lazy 取得 Hermes 主機（每次呼叫都嘗試 resolve，內部有 120s cache）。

    優先序：
      1. env HERMES_URL（僅接受 GCP-A/GCP-B/111）
      2. resolve_ollama_host()（GCP 優先 / 111 備援）
      3. 兜底 http://192.168.0.111:11434（防 ImportError）
    """
    try:
        from services.ollama_service import approved_ollama_env
        env_val = approved_ollama_env('HERMES_URL')
    except Exception:
        env_val = os.getenv('HERMES_URL', '').strip()
    if env_val:
        return env_val
    try:
        from services.ollama_service import resolve_ollama_host
        return resolve_ollama_host()
    except Exception:
        return 'http://192.168.0.111:11434'


def get_embedding_host():
    """Lazy 取得 Embedding 主機。
    優先序：env EMBEDDING_HOST（僅接受 GCP-A/GCP-B/111）> get_hermes_url()。
    """
    try:
        from services.ollama_service import approved_ollama_env
        env_val = approved_ollama_env('EMBEDDING_HOST')
    except Exception:
        env_val = os.getenv('EMBEDDING_HOST', '').strip()
    if env_val:
        return env_val
    return get_hermes_url()


def get_ollama_host():
    """Lazy 取得 Ollama 主機（一般 LLM 推理用）。
    優先序：env OLLAMA_HOST（僅接受 GCP-A/GCP-B/111）> resolve_ollama_host()。
    與舊 module-level OLLAMA_HOST 不同：本函數不會 freeze 結果，每次呼叫都重新 resolve。
    """
    try:
        from services.ollama_service import approved_ollama_env
        env_val = approved_ollama_env('OLLAMA_HOST')
    except Exception:
        env_val = os.getenv('OLLAMA_HOST', '').strip()
    if env_val:
        return env_val
    try:
        from services.ollama_service import resolve_ollama_host
        return resolve_ollama_host()
    except Exception:
        return 'http://192.168.0.111:11434'


# 向下相容：舊 caller 仍可 `from config import HERMES_URL` 取得當下解析值。
# ※ 重要：這仍是 import-time freeze。新 caller 應改用 `get_hermes_url()`。
HERMES_URL = get_hermes_url()
HERMES_TIMEOUT = int(os.getenv('HERMES_TIMEOUT', '120'))  # 秒；批量 300 筆預估 ~90s

# Embedding 服務（ADR-003 對齊：embedding 走 Hermes 主機，內網免認證）
# 向下相容；新 caller 應改用 `get_embedding_host()`
EMBEDDING_HOST = get_embedding_host()
EMBEDDING_TIMEOUT = int(os.getenv('EMBEDDING_TIMEOUT', os.getenv('OLLAMA_EMBED_TIMEOUT', '45')))

# Ollama 本地 AI 服務
# ADR-027 Phase 2：OLLAMA_HOST 改為 lazy resolve，禁止寫死 nginx URL 繞過 GCP 優先策略。
# 舊行為：寫死 'https://ollama.wooo.work/ollama' → 任何 import 都跳過 GCP 探測。
# 新行為：env OLLAMA_HOST 優先；否則走 resolve_ollama_host()（GCP 優先 / 111 備援）。
# 向下相容：保留 OLLAMA_HOST module attribute，但於 import 時呼叫 get_ollama_host()。
# 新 caller 應改用 `from config import get_ollama_host` + `host = get_ollama_host()`。
OLLAMA_HOST = get_ollama_host()
OLLAMA_MODEL = os.getenv('OLLAMA_MODEL', 'gemma3:4b')

# Google Gemini AI 雲端服務
GEMINI_API_KEY = os.getenv('GEMINI_API_KEY', '')
GEMINI_MODEL = os.getenv('GEMINI_MODEL', 'gemini-1.5-flash')
# Gemini is emergency fallback only. The hard kill switch defaults to true, so
# GEMINI_API_KEY/GEMINI_FALLBACK_ENABLED cannot create paid egress by accident.
GEMINI_API_HARD_DISABLED = os.getenv('GEMINI_API_HARD_DISABLED', 'true')
GEMINI_FALLBACK_ENABLED = os.getenv('GEMINI_FALLBACK_ENABLED', 'false')
GEMINI_ALLOWED_CONTEXTS = os.getenv('GEMINI_ALLOWED_CONTEXTS', '')

# 預設 AI 提供者: 'ollama' (本地免費) 或 'gemini' (雲端付費)
AI_PROVIDER = os.getenv('AI_PROVIDER', 'ollama')

# YouTube API Key (用於趨勢爬蟲)
YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')

# ==========================================
# 系統版本與路徑
# ==========================================
SYSTEM_VERSION = "V10.454"
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
public_url = PUBLIC_URL  # 用於模板顯示

def validate_critical_config():
    """啟動時驗證選用配置，缺少則回傳 warning 清單（非 fatal）。"""
    warnings = []
    optional_vars = ['HERMES_URL', 'GOOGLE_DRIVE_CREDENTIALS']
    for var in optional_vars:
        if not os.getenv(var):
            warnings.append(f"[Config] 選用設定 {var} 未設，部分功能可能停用")
    return warnings
