from __future__ import annotations

import json
import os
from pathlib import Path
from typing import Any
from urllib.parse import urlsplit, urlunsplit

DEFAULT_PROFILE = "default"
DEFAULT_TIMEOUT_SECONDS = 30.0
DEFAULT_USER_AGENT = "qingflow-mcp/1.0"
DEFAULT_RECORD_LIST_TYPE = 8
ATTACHMENT_QUESTION_TYPE = 13
DEFAULT_BASE_URL = "https://qingflow.com/api"
DEFAULT_FEEDBACK_APP_KEY = "e0d017kju002"
DEFAULT_FEEDBACK_QSOURCE_TOKEN = "mcp-feedback-7755d14748fc"
DEFAULT_REPOSITORY_GIT_REMOTE_TEMPLATE = "git@hackers.oalite.com:{group}/{repo}.git"
DEFAULT_REPOSITORY_PREVIEW_ADDRESS_TEMPLATE = "https://%s.preview.oalite.com"
DEFAULT_REPOSITORY_DEVELOP_BRANCH = "develop"
DEFAULT_REPOSITORY_PROD_BRANCH = "prod"
DEFAULT_REPOSITORY_AUTHOR_NAME = "qingflow-mcp"
DEFAULT_REPOSITORY_AUTHOR_EMAIL = "qingflow-mcp@local.invalid"
DEFAULT_REPOSITORY_INTERNAL_SHARE_TOKEN_KEY = "tokenKey"
DEFAULT_CREDIT_USAGE_RECORD_PATH = "/user/credit/usage"
DEFAULT_MCPORTER_CONFIG_PATH = "~/.openclaw/workspace/config/mcporter.json"
DEFAULT_CLOUD_AUTH_CONTEXT_TTL_SECONDS = 604800
DEFAULT_CLOUD_AUTH_CONTEXT_LOCK_SECONDS = 10
DEFAULT_CLOUD_AUTH_CONTEXT_NEGATIVE_TTL_SECONDS = 30
DEFAULT_CLOUD_AUTH_CONTEXT_LOCK_WAIT_SECONDS = 5.0
DEFAULT_CLOUD_HTTP_HOST = "0.0.0.0"
DEFAULT_CLOUD_HTTP_PORT = 8000
DEFAULT_CLOUD_HTTP_ALLOWED_HOSTS = ("127.0.0.1", "localhost")


def get_mcp_home() -> Path:
    custom_home = os.getenv("QINGFLOW_MCP_HOME")
    return Path(custom_home).expanduser() if custom_home else Path.home() / ".qingflow-mcp"


def get_profiles_path() -> Path:
    return get_mcp_home() / "profiles.json"


def get_mcporter_config_path() -> Path:
    custom_path = os.getenv("QINGFLOW_MCP_MCPORTER_CONFIG_PATH") or os.getenv(
        "QINGFLOW_MCP_AUTH_CONFIG_PATH"
    )
    return Path(custom_path).expanduser() if custom_path else Path(DEFAULT_MCPORTER_CONFIG_PATH)


def get_repository_metadata_dir() -> Path:
    return get_mcp_home() / "repository-metadata"


def get_config_file_paths() -> list[Path]:
    """
    获取可能的配置文件路径列表，按优先级排序：
    1. 环境变量 QINGFLOW_MCP_CONFIG_PATH 指定的路径
    2. 当前工作目录下的 qingflow-mcp.config.json
    3. MCP home 目录下的 config.json
    4. 系统级配置 (Linux/Mac: /etc/qingflow-mcp/config.json)
    """
    paths: list[Path] = []

    # 1. 环境变量
    env_config = os.getenv("QINGFLOW_MCP_CONFIG_PATH")
    if env_config:
        paths.append(Path(env_config).expanduser())

    # 2. 当前工作目录
    paths.append(Path.cwd() / "qingflow-mcp.config.json")

    # 3. MCP home 目录
    paths.append(get_mcp_home() / "config.json")

    # 4. 系统级配置 (仅非 Windows)
    if os.name != "nt":
        paths.append(Path("/etc/qingflow-mcp/config.json"))

    return paths


def load_config_file() -> dict[str, Any]:
    """
    加载第一个存在的配置文件

    Returns:
        配置字典，如果没有找到配置文件则返回空字典
    """
    for path in get_config_file_paths():
        if path.exists():
            try:
                with open(path, "r", encoding="utf-8") as f:
                    content = f.read()
                    # 移除 JSON 注释 (简单的行注释处理)
                    lines = []
                    for line in content.split("\n"):
                        stripped = line.strip()
                        if not stripped.startswith("//") and not stripped.startswith("#"):
                            lines.append(line)
                    return json.loads("\n".join(lines))
            except (json.JSONDecodeError, IOError) as e:
                # 配置文件存在但读取失败，记录警告但不中断
                print(f"Warning: Failed to load config from {path}: {e}")
                continue
    return {}


def get_config_value(key: str, env_var: str | None = None, default: Any = None) -> Any:
    """
    获取配置值，优先级：环境变量 > 配置文件 > 默认值

    Args:
        key: 配置文件中的键名 (支持点号分隔的嵌套键，如 "profiles.default.name")
        env_var: 环境变量名
        default: 默认值

    Returns:
        配置值
    """
    # 1. 环境变量
    if env_var:
        env_value = os.getenv(env_var)
        if env_value is not None:
            return env_value

    # 2. 配置文件
    config = load_config_file()
    keys = key.split(".")
    value = config
    for k in keys:
        if isinstance(value, dict) and k in value:
            value = value[k]
        else:
            value = None
            break

    if value is not None:
        return value

    # 3. 默认值
    return default


def get_default_base_url() -> str | None:
    """获取默认的 Qingflow 后端地址"""
    value = get_config_value(
        "default_base_url",
        env_var="QINGFLOW_MCP_DEFAULT_BASE_URL",
        default=DEFAULT_BASE_URL
    )
    return normalize_base_url(value) if value else None


def get_default_qf_version() -> str | None:
    """获取默认的 qfVersion 路由值"""
    value = get_config_value(
        "default_qf_version",
        env_var="QINGFLOW_MCP_DEFAULT_QF_VERSION",
        default=None,
    )
    if value is None:
        return None
    normalized = str(value).strip()
    return normalized or None


def get_feedback_qsource_token() -> str | None:
    """获取反馈 q-source 被动入口 token"""
    value = get_config_value(
        "feedback.qsource_token",
        env_var="QINGFLOW_MCP_FEEDBACK_QSOURCE_TOKEN",
        default=DEFAULT_FEEDBACK_QSOURCE_TOKEN,
    )
    if value is None:
        return None
    normalized = str(value).strip()
    return normalized or None


def get_feedback_base_url() -> str | None:
    """获取反馈 q-source 使用的 base URL"""
    value = get_config_value(
        "feedback.base_url",
        env_var="QINGFLOW_MCP_FEEDBACK_BASE_URL",
        default=None,
    )
    if value is None:
        return get_default_base_url()
    normalized = normalize_base_url(value)
    return normalized or get_default_base_url()


def get_feedback_app_key() -> str:
    """获取内部反馈表 app_key"""
    value = get_config_value(
        "feedback.app_key",
        env_var="QINGFLOW_MCP_FEEDBACK_APP_KEY",
        default=DEFAULT_FEEDBACK_APP_KEY,
    )
    normalized = str(value or "").strip()
    return normalized or DEFAULT_FEEDBACK_APP_KEY


def get_timeout_seconds() -> float:
    """获取 HTTP 超时秒数"""
    value = get_config_value(
        "timeout_seconds",
        env_var="QINGFLOW_MCP_TIMEOUT_SECONDS",
        default=DEFAULT_TIMEOUT_SECONDS
    )
    try:
        return float(value)
    except (ValueError, TypeError):
        return DEFAULT_TIMEOUT_SECONDS


def get_log_level() -> str:
    """获取日志级别"""
    return get_config_value(
        "log_level",
        env_var="QINGFLOW_MCP_LOG_LEVEL",
        default="INFO"
    )


def get_credit_meter_enabled() -> bool:
    value = get_config_value(
        "credit_meter.enabled",
        env_var="QINGFLOW_MCP_CREDIT_METER_ENABLED",
        default="true",
    )
    normalized = str(value or "").strip().lower()
    return normalized in {"1", "true", "yes", "on"}


def get_credit_usage_base_url() -> str | None:
    value = get_config_value(
        "credit_meter.apaas.base_url",
        env_var="QINGFLOW_MCP_CREDIT_APAAS_BASE_URL",
        default=None,
    )
    normalized = normalize_base_url(value)
    return normalized or get_default_base_url()


def get_credit_usage_path() -> str:
    value = get_config_value(
        "credit_meter.apaas.path",
        env_var="QINGFLOW_MCP_CREDIT_APAAS_PATH",
        default=DEFAULT_CREDIT_USAGE_RECORD_PATH,
    )
    normalized = str(value or "").strip()
    return normalized or DEFAULT_CREDIT_USAGE_RECORD_PATH


def get_cloud_redis_url() -> str | None:
    value = get_config_value(
        "cloud.redis_url",
        env_var="QINGFLOW_MCP_REDIS_URL",
        default=None,
    )
    normalized = str(value or "").strip()
    return normalized or None


def get_cloud_auth_context_ttl_seconds() -> int:
    return _get_positive_int_config(
        "cloud.auth_context_ttl_seconds",
        "QINGFLOW_MCP_AUTH_CONTEXT_TTL_SECONDS",
        DEFAULT_CLOUD_AUTH_CONTEXT_TTL_SECONDS,
    )


def get_cloud_auth_context_lock_seconds() -> int:
    return _get_positive_int_config(
        "cloud.auth_context_lock_seconds",
        "QINGFLOW_MCP_AUTH_CONTEXT_LOCK_SECONDS",
        DEFAULT_CLOUD_AUTH_CONTEXT_LOCK_SECONDS,
    )


def get_cloud_auth_context_negative_ttl_seconds() -> int:
    return _get_positive_int_config(
        "cloud.auth_context_negative_ttl_seconds",
        "QINGFLOW_MCP_AUTH_CONTEXT_NEGATIVE_TTL_SECONDS",
        DEFAULT_CLOUD_AUTH_CONTEXT_NEGATIVE_TTL_SECONDS,
    )


def get_cloud_auth_context_lock_wait_seconds() -> float:
    value = get_config_value(
        "cloud.auth_context_lock_wait_seconds",
        env_var="QINGFLOW_MCP_AUTH_CONTEXT_LOCK_WAIT_SECONDS",
        default=DEFAULT_CLOUD_AUTH_CONTEXT_LOCK_WAIT_SECONDS,
    )
    try:
        parsed = float(value)
    except (TypeError, ValueError):
        return DEFAULT_CLOUD_AUTH_CONTEXT_LOCK_WAIT_SECONDS
    return parsed if parsed > 0 else DEFAULT_CLOUD_AUTH_CONTEXT_LOCK_WAIT_SECONDS


def get_cloud_http_host() -> str:
    value = get_config_value(
        "cloud.http.host",
        env_var="QINGFLOW_MCP_HTTP_HOST",
        default=DEFAULT_CLOUD_HTTP_HOST,
    )
    normalized = str(value or "").strip()
    return normalized or DEFAULT_CLOUD_HTTP_HOST


def get_cloud_http_port() -> int:
    value = get_config_value(
        "cloud.http.port",
        env_var="QINGFLOW_MCP_HTTP_PORT",
        default=DEFAULT_CLOUD_HTTP_PORT,
    )
    try:
        parsed = int(value)
    except (TypeError, ValueError):
        return DEFAULT_CLOUD_HTTP_PORT
    return parsed if 0 < parsed < 65536 else DEFAULT_CLOUD_HTTP_PORT


def get_cloud_http_allowed_hosts() -> list[str]:
    value = get_config_value(
        "cloud.http.allowed_hosts",
        env_var="QINGFLOW_MCP_HTTP_ALLOWED_HOSTS",
        default=",".join(DEFAULT_CLOUD_HTTP_ALLOWED_HOSTS),
    )
    if isinstance(value, (list, tuple, set)):
        raw_hosts = value
    else:
        raw_hosts = str(value or "").split(",")
    hosts = [str(host or "").strip().lower() for host in raw_hosts]
    return [host for host in hosts if host] or list(DEFAULT_CLOUD_HTTP_ALLOWED_HOSTS)


def _get_positive_int_config(key: str, env_var: str, default: int) -> int:
    value = get_config_value(key, env_var=env_var, default=default)
    try:
        parsed = int(value)
    except (TypeError, ValueError):
        return default
    return parsed if parsed > 0 else default


def get_repository_default_group() -> str | None:
    value = get_config_value(
        "repository.default_group",
        env_var="QINGFLOW_MCP_REPOSITORY_DEFAULT_GROUP",
        default=None,
    )
    normalized = str(value or "").strip()
    return normalized or None


def get_repository_git_remote_template() -> str:
    value = get_config_value(
        "repository.git_remote_template",
        env_var="QINGFLOW_MCP_REPOSITORY_GIT_REMOTE_TEMPLATE",
        default=DEFAULT_REPOSITORY_GIT_REMOTE_TEMPLATE,
    )
    normalized = str(value or "").strip()
    return normalized or DEFAULT_REPOSITORY_GIT_REMOTE_TEMPLATE


def get_repository_preview_address_template() -> str:
    value = get_config_value(
        "repository.preview_address_template",
        env_var="QINGFLOW_MCP_REPOSITORY_PREVIEW_ADDRESS_TEMPLATE",
        default=DEFAULT_REPOSITORY_PREVIEW_ADDRESS_TEMPLATE,
    )
    normalized = str(value or "").strip()
    return normalized or DEFAULT_REPOSITORY_PREVIEW_ADDRESS_TEMPLATE


def get_repository_develop_branch() -> str:
    value = get_config_value(
        "repository.develop_branch",
        env_var="QINGFLOW_MCP_REPOSITORY_DEVELOP_BRANCH",
        default=DEFAULT_REPOSITORY_DEVELOP_BRANCH,
    )
    normalized = str(value or "").strip()
    return normalized or DEFAULT_REPOSITORY_DEVELOP_BRANCH


def get_repository_prod_branch() -> str:
    value = get_config_value(
        "repository.prod_branch",
        env_var="QINGFLOW_MCP_REPOSITORY_PROD_BRANCH",
        default=DEFAULT_REPOSITORY_PROD_BRANCH,
    )
    normalized = str(value or "").strip()
    return normalized or DEFAULT_REPOSITORY_PROD_BRANCH


def get_repository_author_name() -> str:
    value = get_config_value(
        "repository.author_name",
        env_var="QINGFLOW_MCP_REPOSITORY_AUTHOR_NAME",
        default=DEFAULT_REPOSITORY_AUTHOR_NAME,
    )
    normalized = str(value or "").strip()
    return normalized or DEFAULT_REPOSITORY_AUTHOR_NAME


def get_repository_author_email() -> str:
    value = get_config_value(
        "repository.author_email",
        env_var="QINGFLOW_MCP_REPOSITORY_AUTHOR_EMAIL",
        default=DEFAULT_REPOSITORY_AUTHOR_EMAIL,
    )
    normalized = str(value or "").strip()
    return normalized or DEFAULT_REPOSITORY_AUTHOR_EMAIL


def get_repository_internal_base_url() -> str | None:
    value = get_config_value(
        "repository.internal_base_url",
        env_var="QINGFLOW_MCP_REPOSITORY_INTERNAL_BASE_URL",
        default=None,
    )
    if value is None:
        return None
    normalized = normalize_base_url(str(value).strip())
    return normalized or None


def get_repository_internal_share_token() -> str | None:
    value = get_config_value(
        "repository.internal_share_token",
        env_var="QINGFLOW_MCP_REPOSITORY_INTERNAL_SHARE_TOKEN",
        default=None,
    )
    normalized = str(value or "").strip()
    return normalized or None


def get_repository_internal_share_token_key() -> str:
    value = get_config_value(
        "repository.internal_share_token_key",
        env_var="QINGFLOW_MCP_REPOSITORY_INTERNAL_SHARE_TOKEN_KEY",
        default=DEFAULT_REPOSITORY_INTERNAL_SHARE_TOKEN_KEY,
    )
    normalized = str(value or "").strip()
    return normalized or DEFAULT_REPOSITORY_INTERNAL_SHARE_TOKEN_KEY


def get_repository_generate_default_agent_id() -> int | None:
    value = get_config_value(
        "repository.generate.default_agent_id",
        env_var="QINGFLOW_MCP_REPOSITORY_GENERATE_DEFAULT_AGENT_ID",
        default=None,
    )
    if value is None:
        return None
    try:
        return int(str(value).strip())
    except (TypeError, ValueError):
        return None


def get_repository_generate_default_route_prefix() -> str | None:
    value = get_config_value(
        "repository.generate.default_route_prefix",
        env_var="QINGFLOW_MCP_REPOSITORY_GENERATE_DEFAULT_ROUTE_PREFIX",
        default=None,
    )
    normalized = str(value or "").strip()
    return normalized or None


def get_repository_generate_default_token_name() -> str | None:
    value = get_config_value(
        "repository.generate.default_token_name",
        env_var="QINGFLOW_MCP_REPOSITORY_GENERATE_DEFAULT_TOKEN_NAME",
        default=None,
    )
    normalized = str(value or "").strip()
    return normalized or None


def normalize_base_url(base_url: str | None) -> str | None:
    """规范化 base URL"""
    if base_url is None:
        return None
    normalized = base_url.strip()
    if not normalized:
        return None
    normalized = normalized.rstrip("/")
    try:
        parsed = urlsplit(normalized)
    except ValueError:
        return normalized
    if not parsed.scheme or not parsed.netloc:
        return normalized

    hostname = parsed.hostname or ""
    if hostname.lower() == "www.qingflow.com":
        netloc = "qingflow.com"
        if parsed.port is not None:
            netloc = f"{netloc}:{parsed.port}"
        normalized = urlunsplit((parsed.scheme, netloc, parsed.path, parsed.query, parsed.fragment))
    return normalized
