# ============================================================
# core/company_manager.py
# Quản lý danh sách công ty và tạo mới công ty
# Upgrade 8: Hỗ trợ multi-profile DB (nhiều HKD/file .db)
# ============================================================

import os
import json
import re
from typing import Optional, List

from core.db_init import init_company_db

from core.utils import get_app_data_path, get_company_tax_id

ROOT_SETTINGS_FILE = get_app_data_path("settings.json")


def _sanitize_tax_id(tax_id: str) -> str:
    digits_only = "".join(ch for ch in str(tax_id or "").strip() if ch.isdigit())
    if digits_only:
        return digits_only
    cleaned = re.sub(r'[\\/*?:"<>|]', "", str(tax_id or "").strip())
    return cleaned


def get_company_root_for_tax_id(tax_id: str, relative_path: str = "") -> str:
    safe_tax_id = _sanitize_tax_id(tax_id)
    company_root = os.path.join(get_app_data_path(""), safe_tax_id) if safe_tax_id else get_app_data_path("")
    os.makedirs(company_root, exist_ok=True)
    if relative_path:
        return os.path.join(company_root, relative_path)
    return company_root


def get_company_db_path_for_tax_id(tax_id: str) -> str:
    safe_tax_id = _sanitize_tax_id(tax_id)
    if not safe_tax_id:
        return ""
    return get_company_root_for_tax_id(safe_tax_id, os.path.join("database", f"{safe_tax_id}.db"))

def _get_default_db_path() -> str:
    """Đường dẫn DB mặc định là {MST}.db thay cho data.db"""
    return get_company_db_path_for_tax_id(get_company_tax_id())


def _load_settings() -> dict:
    """Đọc settings.json, trả về {} nếu lỗi."""
    if not os.path.exists(ROOT_SETTINGS_FILE):
        return {}
    try:
        with open(ROOT_SETTINGS_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception:
        return {}


def _save_settings(data: dict) -> None:
    os.makedirs(os.path.dirname(ROOT_SETTINGS_FILE), exist_ok=True)
    with open(ROOT_SETTINGS_FILE, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)


def _infer_tax_id_from_db_path(db_path: str) -> str:
    base_name = os.path.splitext(os.path.basename(db_path or ""))[0]
    return _sanitize_tax_id(base_name)


def _build_profile(company_info: dict | None = None, db_path: str = "", is_active: bool = False) -> dict | None:
    info = dict(company_info or {})
    tax_id = _sanitize_tax_id(info.get("tax_id") or _infer_tax_id_from_db_path(db_path))
    if not tax_id:
        return None

    resolved_db_path = db_path or info.get("db_path") or info.get("path") or get_company_db_path_for_tax_id(tax_id)
    legal_name = (info.get("legal_name") or info.get("name") or tax_id).strip()

    profile = {k: v for k, v in info.items() if k not in {"path", "db_path", "is_active"}}
    profile["tax_id"] = tax_id
    profile["legal_name"] = legal_name
    profile["name"] = profile.get("name") or legal_name
    profile["db_path"] = resolved_db_path
    profile["path"] = resolved_db_path
    profile["is_active"] = bool(is_active)
    return profile


def save_profiles(profiles: List[dict]) -> list:
    """Lưu danh sách công ty toàn cục vào settings.json gốc của ứng dụng."""
    settings = _load_settings()
    system = dict(settings.get("system", {}) or {})

    normalized_profiles: list[dict] = []
    seen_tax_ids: set[str] = set()
    active_tax_id = ""

    for raw_profile in profiles or []:
        profile = _build_profile(raw_profile, raw_profile.get("db_path") or raw_profile.get("path") or "", bool(raw_profile.get("is_active")))
        if not profile:
            continue
        tax_id = profile["tax_id"]
        if tax_id in seen_tax_ids:
            continue
        seen_tax_ids.add(tax_id)
        if profile.get("is_active") and not active_tax_id:
            active_tax_id = tax_id
        normalized_profiles.append(profile)

    if not normalized_profiles:
        current_company = settings.get("company", {}) if isinstance(settings.get("company"), dict) else {}
        if current_company.get("tax_id"):
            normalized_profiles.append(
                _build_profile(
                    current_company,
                    system.get("last_db_path") or get_company_db_path_for_tax_id(current_company.get("tax_id", "")),
                    True,
                )
            )

    normalized_profiles = [profile for profile in normalized_profiles if profile]
    if normalized_profiles and not active_tax_id:
        active_tax_id = normalized_profiles[0]["tax_id"]

    for profile in normalized_profiles:
        profile["is_active"] = profile["tax_id"] == active_tax_id

    active_profile = next((profile for profile in normalized_profiles if profile.get("is_active")), None)
    if active_profile:
        settings["company"] = {
            key: value
            for key, value in active_profile.items()
            if key not in {"db_path", "path", "is_active", "name"}
        }
        system["active_company_tax_id"] = active_profile["tax_id"]
        system["last_db_path"] = active_profile.get("db_path") or active_profile.get("path") or ""
    else:
        settings["company"] = {}
        system["active_company_tax_id"] = ""
        system["last_db_path"] = ""

    system["company_profiles"] = [
        {
            key: value
            for key, value in profile.items()
            if key != "path"
        }
        for profile in normalized_profiles
    ]
    settings["system"] = system
    _save_settings(settings)
    return normalized_profiles


# ── Multi-profile: quản lý danh sách DB profiles ──────────

def get_profiles() -> List[dict]:
    """
    Trả về danh sách các profile DB đã lưu.
    Mỗi profile: { "name": str, "path": str, "is_active": bool }
    """
    settings = _load_settings()
    system = settings.get("system", {}) if isinstance(settings.get("system"), dict) else {}
    raw_profiles = system.get("company_profiles", [])

    profiles: list[dict] = []
    if isinstance(raw_profiles, list):
        profiles = save_profiles(raw_profiles)

    if profiles:
        return profiles

    current_company = settings.get("company", {}) if isinstance(settings.get("company"), dict) else {}
    if current_company.get("tax_id"):
        return save_profiles([
            _build_profile(
                current_company,
                system.get("last_db_path") or get_company_db_path_for_tax_id(current_company.get("tax_id", "")),
                True,
            )
        ])

    return []


def get_active_profile() -> dict:
    """Trả về profile đang được chọn."""
    for p in get_profiles():
        if p.get("is_active"):
            return p
    return {}


def add_profile(name: str, db_path: str, standard: str = "TT133") -> None:
    """
    Thêm profile mới (tạo DB mới nếu chưa tồn tại).
    """
    # Tạo DB mới nếu chưa có
    if not os.path.exists(db_path):
        os.makedirs(os.path.dirname(os.path.abspath(db_path)), exist_ok=True)
        init_company_db(db_path, standard=standard)

    profiles = get_profiles()
    if any((p.get("db_path") or p.get("path")) == db_path for p in profiles):
        return

    tax_id = _infer_tax_id_from_db_path(db_path)
    profiles.append(
        {
            "name": name,
            "legal_name": name,
            "tax_id": tax_id,
            "db_path": db_path,
            "is_active": False,
        }
    )
    save_profiles(profiles)


def switch_profile(db_path: str) -> None:
    """Chuyển active profile sang path được chỉ định."""
    profiles = get_profiles()
    for p in profiles:
        p["is_active"] = ((p.get("db_path") or p.get("path")) == db_path)
    save_profiles(profiles)


def remove_profile(db_path: str) -> None:
    """Xóa profile khỏi danh sách (không xóa file DB)."""
    profiles = [p for p in get_profiles() if (p.get("db_path") or p.get("path")) != db_path]
    # Đảm bảo luôn có ít nhất 1 profile active
    if profiles and not any(p.get("is_active") for p in profiles):
        profiles[0]["is_active"] = True
    save_profiles(profiles)


# ── Backward-compatible API ────────────────────────────────

def get_active_db_path() -> str:
    """Trả về đường dẫn DB đang active."""
    profile = get_active_profile()
    db_path = profile.get("db_path") or profile.get("path") or _get_default_db_path()
    if not db_path:
        return ""
    if not os.path.exists(db_path):
        print(f"📦 Khởi tạo cơ sở dữ liệu mới tại: {db_path}")
        os.makedirs(os.path.dirname(os.path.abspath(db_path)), exist_ok=True)
        init_company_db(db_path, standard="TT133")
    return db_path


def get_company_db_path(code: str = "") -> Optional[str]:
    """Fallback cho các hàm cũ — trả về active DB."""
    return get_active_db_path()


def list_companies() -> list:
    """Trả về danh sách các profile (dùng cho UI sidebar)."""
    profiles = get_profiles()
    return [
        {
            "code": f"HKD_{i+1:03d}",
            "name": p.get("legal_name") or p.get("name", f"Hộ {i+1}"),
            "path": p.get("db_path") or p.get("path", ""),
            "tax_id": p.get("tax_id", ""),
            "status": "active" if p.get("is_active") else "inactive",
        }
        for i, p in enumerate(profiles)
    ]
