"""General configuration constants for the MCard application."""

import json
from pathlib import Path

_PROJECT_ROOT = Path(__file__).resolve().parents[2]
_APP_CONFIG_PATH = _PROJECT_ROOT / "config" / "app_config.json"


def _load_app_config() -> dict:
    with _APP_CONFIG_PATH.open(encoding="utf-8") as handle:
        return json.load(handle)


_APP_CONFIG = _load_app_config()


def _cfg(*path: str, default=None):
    current: object = _APP_CONFIG
    for key in path:
        if not isinstance(current, dict) or key not in current:
            return default
        current = current[key]
    return current


# Environment Variable Names for Hashing
ENV_HASH_ALGORITHM = "MCARD_HASH_ALGORITHM"
ENV_HASH_CUSTOM_MODULE = "MCARD_HASH_CUSTOM_MODULE"
ENV_HASH_CUSTOM_FUNCTION = "MCARD_HASH_CUSTOM_FUNCTION"
ENV_HASH_CUSTOM_LENGTH = "MCARD_HASH_CUSTOM_LENGTH"

# ─────────────────────────────────────────────────────────────────────────────
# Database Schema
# ─────────────────────────────────────────────────────────────────────────────
# DEPRECATED: Use mcard.schema.MCardSchema instead.
# All schemas are loaded from: schema/mcard_schema.sql (the ONLY source)
#
# For schema access, use:
#   from mcard.schema import MCardSchema
#   schema = MCardSchema.get_instance()
#   schema.get_table('card')
# ─────────────────────────────────────────────────────────────────────────────

# Lazy-loaded for backward compatibility
_MCARD_TABLE_SCHEMA = None


def __getattr__(name):
    """
    Lazy attribute access for backward compatibility.

    MCARD_TABLE_SCHEMA is loaded exclusively from the singleton.
    There are NO hardcoded SQL fallbacks.
    """
    global _MCARD_TABLE_SCHEMA
    if name == "MCARD_TABLE_SCHEMA":
        if _MCARD_TABLE_SCHEMA is None:
            from mcard.schema import MCardSchema

            schema = MCardSchema.get_instance()
            _MCARD_TABLE_SCHEMA = {
                "documents": schema.get_table("mcard_fts"),
                "card": schema.get_table("card"),
            }
        return _MCARD_TABLE_SCHEMA
    raise AttributeError(
        f"module 'mcard.config.config_constants' has no attribute '{name}'"
    )


# Triggers for Synchronizing FTS Table with Card Table
# Note: Consider using mcard_fts instead for new deployments
TRIGGERS = [
    "CREATE TRIGGER IF NOT EXISTS card_insert AFTER INSERT ON card BEGIN INSERT INTO documents(content) VALUES (new.content); END;",
    "CREATE TRIGGER IF NOT EXISTS card_update AFTER UPDATE ON card BEGIN UPDATE documents SET content = new.content WHERE rowid = (SELECT rowid FROM documents WHERE content = old.content LIMIT 1); END;",
    "CREATE TRIGGER IF NOT EXISTS card_delete AFTER DELETE ON card BEGIN DELETE FROM documents WHERE content = old.content; END;",
]


# Database Paths
DEFAULT_DB_PATH = _cfg(
    "storage", "default_db_path", default="./data/DEFAULT_DB_FILE.db"
)
TEST_DB_PATH = _cfg("storage", "test_db_path", default="./tests/data/test_mcard.db")

# Identity Space Configurations
DEFAULT_IDENTITY_PROVIDER = _cfg("identity", "provider", default="sqlite")
DEFAULT_IDENTITY_SPACE_PATH = _cfg(
    "identity", "space_path", default="./data/IDENTITY_SPACE.db"
)
DEFAULT_VAPID_CONTACT = _cfg(
    "identity", "default_vapid_contact", default="mailto:developer@example.com"
)

# Environment Variable Names
ENV_DB_PATH = "MCARD_DB_PATH"
ENV_TEST_DB_PATH = "TEST_DB_PATH"

# Environment Variable Names for Identity Space
ENV_IDENTITY_PROVIDER = _cfg(
    "env", "identity_provider", default="MCARD_IDENTITY_PROVIDER"
)
ENV_IDENTITY_SPACE_PATH = _cfg(
    "env", "identity_space_path", default="IDENTITY_SPACE_PATH"
)
ENV_IDENTITY_API_ENDPOINT = _cfg(
    "env", "identity_api_endpoint", default="MCARD_IDENTITY_API_ENDPOINT"
)

ENV_DEFAULT_POOL_SIZE = "DEFAULT_POOL_SIZE"
ENV_DB_MAX_CONNECTIONS = "MCARD_STORE_MAX_CONNECTIONS"
ENV_DB_TIMEOUT = "MCARD_STORE_TIMEOUT"
ENV_SERVICE_LOG_LEVEL = "MCARD_SERVICE_LOG_LEVEL"
ENV_API_PORT = "MCARD_API_PORT"
ENV_FORCE_DEFAULT_CONFIG = "MCARD_FORCE_DEFAULT_CONFIG"
ENV_API_KEY = "MCARD_API_KEY"
ENV_WRAP_WIDTH_DEFAULT = "MCARD_WRAP_WIDTH_DEFAULT"
ENV_WRAP_WIDTH_KNOWN = "MCARD_WRAP_WIDTH_KNOWN"
ENV_MAX_PROBLEM_TEXT_BYTES = "MCARD_MAX_PROBLEM_TEXT_BYTES"
ENV_READ_TIMEOUT_SECS = "MCARD_READ_TIMEOUT_SECS"
ENV_MAX_FILE_SIZE = "MCARD_MAX_SIZE_BYTES"

# Default Configuration Values
DEFAULT_POOL_SIZE = 10
DEFAULT_TIMEOUT = 30.0
DEFAULT_API_PORT = _cfg("network", "default_api_port", default=5320)
DEFAULT_WS_HOST = _cfg("network", "default_ws_host", default="127.0.0.1")
DEFAULT_WS_PORT = _cfg("network", "default_ws_port", default=5321)
DEFAULT_API_KEY = "your_api_key_here"
DEFAULT_HASH_ALGORITHM = "sha256"
DEFAULT_HASH_CUSTOM_MODULE = "custom_module"
DEFAULT_HASH_CUSTOM_FUNCTION = "custom_function"
DEFAULT_HASH_CUSTOM_LENGTH = 64
DEFAULT_LOG_LEVEL = "DEBUG"
DEFAULT_WRAP_WIDTH_DEFAULT = 1000
DEFAULT_WRAP_WIDTH_KNOWN = 1200
DEFAULT_MAX_PROBLEM_TEXT_BYTES = 2 * 1024 * 1024
DEFAULT_READ_TIMEOUT_SECS = 30.0
DEFAULT_MAX_FILE_SIZE = 150 * 1024 * 1024

# Server Configuration
DEFAULT_SERVER_HOST = _cfg(
    "network", "default_server_host", default="0.0.0.0"
)  # nosec B104
SERVER_HOST = DEFAULT_SERVER_HOST
DEFAULT_PAGE_SIZE = 10
MAX_PAGE_SIZE = 1000
MIN_PAGE_SIZE = 1

# IndexedDB (for parity with JS)
INDEXEDDB_DEFAULT_DB_NAME = "mcard-db"
INDEXEDDB_DEFAULT_DB_VERSION = 1

# SQLite Configuration
SQLITE_BUSY_TIMEOUT_MS = 5000  # ms to wait for locks before SQLITE_BUSY

# Environment Variable Names for Shared Ports
ENV_WS_HOST = _cfg("env", "ws_host", default="VITE_WS_HOST")
ENV_WS_PORT = _cfg("env", "ws_port", default="VITE_WS_PORT")

# API/WS Port Environment Variable Compatibility
ENV_API_PORT_LEGACY = "HTTP_PORT"
ENV_WS_PORT_LEGACY = "WS_PORT"

# Service URL Defaults (overridable via env vars or config)
DEFAULT_OLLAMA_BASE_URL = _cfg(
    "services", "default_ollama_base_url", default="http://localhost:11434"
)
DEFAULT_OTLP_ENDPOINT = _cfg(
    "services", "default_otlp_endpoint", default="http://localhost:4317"
)
DEFAULT_VLLM_BASE_URL = _cfg(
    "services", "default_vllm_base_url", default="http://localhost:8000"
)
DEFAULT_LMSTUDIO_BASE_URL = _cfg(
    "services", "default_lmstudio_base_url", default="http://localhost:1234"
)

# ─────────────────────────────────────────────────────────────────────────────
# PTR Runtime Timeouts (seconds)
# ─────────────────────────────────────────────────────────────────────────────

PTR_DEFAULT_TIMEOUT_SECS = 5
PTR_LEAN_TIMEOUT_SECS = 60
PTR_JULIA_TIMEOUT_SECS = 15
PTR_R_TIMEOUT_SECS = 10
PTR_JAVASCRIPT_TIMEOUT_SECS = 120
PTR_COMMAND_CHECK_TIMEOUT_SECS = 10
PTR_LEAN_VALIDATE_TIMEOUT_SECS = 30

# ─────────────────────────────────────────────────────────────────────────────
# RAG / Embedding Timeouts (seconds)
# ─────────────────────────────────────────────────────────────────────────────

RAG_OLLAMA_TIMEOUT_SECS = 60
RAG_OLLAMA_VALIDATE_TIMEOUT_SECS = 5
RAG_VISION_DESCRIBE_TIMEOUT_SECS = 120
RAG_VISION_VALIDATE_TIMEOUT_SECS = 10

# ─────────────────────────────────────────────────────────────────────────────
# Network Runtime Cleanup
# ─────────────────────────────────────────────────────────────────────────────

NETWORK_PROCESS_TERMINATE_WAIT_SECS = 1

# ─────────────────────────────────────────────────────────────────────────────
# Script / Tooling Timeouts (seconds)
# ─────────────────────────────────────────────────────────────────────────────

SERVICE_RUNTIME_CHECK_TIMEOUT_SECS = 10
CLM_TS_RUN_TIMEOUT_SECS = 60

# ─────────────────────────────────────────────────────────────────────────────
# LLM Provider Timeouts (seconds)
# ─────────────────────────────────────────────────────────────────────────────

LLM_DEFAULT_TIMEOUT_SECS = 120
LLM_DEFAULT_RETRY_COUNT = 3
LLM_DEFAULT_RETRY_DELAY_SECS = 1.0

# ─────────────────────────────────────────────────────────────────────────────
# URL / HTTP Fetch Timeouts (seconds)
# ─────────────────────────────────────────────────────────────────────────────

URL_FETCH_TIMEOUT_SECS = 5

# ─────────────────────────────────────────────────────────────────────────────
# Signaling Server Operational Constants
# ─────────────────────────────────────────────────────────────────────────────

SIGNALING_SSE_KEEPALIVE_SECS = 15
SIGNALING_LSOF_TIMEOUT_SECS = 2
SIGNALING_PORT_RELEASE_WAIT_SECS = 0.5

# Content Processing
MAX_VECTOR_CONTENT_CHARS = 10_000  # max chars indexed for FTS in vector store

# HTTP Status Codes
HTTP_STATUS_OK = 200
HTTP_STATUS_FORBIDDEN = 403
HTTP_STATUS_NOT_FOUND = 404
HTTP_STATUS_INTERNAL_SERVER_ERROR = 500

# Error Messages
ERROR_INVALID_API_KEY = "Invalid API key"
ERROR_CARD_NOT_FOUND = "Card not found"
ERROR_CARD_CREATION_FAILED = "Failed to create card"
ERROR_CARD_DELETION_FAILED = "Failed to delete card"

# Event Constants
TYPE = "type"
HASH = "hash"
FIRST_G_TIME = "first_g_time"
CONTENT_SIZE = "content_size"
COLLISION_TIME = "collision_time"
UPGRADED_FUNCTION = "upgraded_function"
UPGRADED_HASH = "upgraded_hash"
DUPLICATE_TIME = "duplicate_time"
DUPLICATE_EVENT_TYPE = "duplicate"
COLLISION_EVENT_TYPE = "collision"

# A Pair of colliding MD5 content values
MD5_COLLISION_PAIR_IN_BYTES_a = bytes.fromhex(
    "4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518afbfa200a8284bf36e8e4b55b35f427593d849676da0d1555d8360fb5f07fea2"
)
MD5_COLLISION_PAIR_IN_BYTES_b = bytes.fromhex(
    "4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518afbfa202a8284bf36e8e4b55b35f427593d849676da0d1d55d8360fb5f07fea2"
)

# Hash Algorithm Hierarchy
ALGORITHM_HIERARCHY = {
    "sha1": {"strength": 1, "next": "sha224"},
    "sha224": {"strength": 2, "next": "sha256"},
    "sha256": {"strength": 3, "next": "sha384"},
    "sha384": {"strength": 4, "next": "sha512"},
    "sha512": {"strength": 5, "next": "custom"},
    "custom": {"strength": 6, "next": None},
}

# Logging Configuration
LOG_DIRECTORY = "logs"
LOG_FILENAME = "mcard.log"
DEFAULT_LOG_PATH = f"{LOG_DIRECTORY}/{LOG_FILENAME}"

# CORS origins
CORS_ORIGINS = _cfg(
    "network",
    "cors_origins",
    default=[
        "http://localhost:3000",
        "http://localhost:8000",
        "https://localhost:3000",
        "https://localhost:8000",
        "http://localhost:8080",
        "https://example.com",
    ],
)

# API Key Header Name
API_KEY_HEADER_NAME = _cfg("web", "api_key_header_name", default="X-API-Key")

# Search Parameters
SEARCH_CONTENT_DEFAULT = True
SEARCH_HASH_DEFAULT = True
SEARCH_TIME_DEFAULT = True

# Additional Error Messages
ERROR_SERVER_SHUTDOWN = "Server shutdown failed"
ERROR_INVALID_CONTENT = "Content cannot be empty"
ERROR_INVALID_METADATA = "Metadata must be a dictionary"
ERROR_LISTING_CARDS = "Error listing cards"
ERROR_DELETE_ALL_CARDS_FAILED = "Failed to delete all cards"
SUCCESS_DELETE_ALL_CARDS = "All cards deleted successfully"
HEALTH_CHECK_SUCCESS = "Server is healthy"
HEALTH_CHECK_FAILURE = "Server health check failed"
ERROR_INVALID_CREDENTIALS = "Invalid credentials"
ERROR_CARD_ALREADY_EXISTS = "Card already exists"
ERROR_CARD_NOT_AUTHORIZED = "Card not authorized"
ERROR_INVALID_REQUEST = "Invalid request"
ERROR_INVALID_CARD_ID = "Invalid card ID"
ERROR_CARD_UPDATE_FAILED = "Failed to update card"
ERROR_CARD_NOT_UPDATED = "Card not updated"
