"""SOAGILA Project Manager — Multi-project isolation and tier enforcement.

Each VS Code workspace gets its own isolated SQLite database.
Projects are identified by SHA256 hash of their absolute path.
Tier limits control how many projects can be active.
Global memory (semantic tier) can be shared across projects.
"""

import json
import logging
from pathlib import Path
from datetime import datetime, timezone

from soagila.config import get_soagila_home, get_project_hash, get_project_dir, get_settings

logger = logging.getLogger("soagila.project_manager")

# Tier limits
TIER_LIMITS = {
    "free": {
        "max_users": 1,
        "max_projects": 1,
        "retention_days": 7,
        "max_memories": 500,
        "sdijap": False,
        "backup": False,
        "cifce": False,
        "compliance": False,
        "inheritance": False,
        "sso": False,
        "on_premise": False,
        "price_monthly": 0,
        "price_annual": 0,
    },
    "pro": {
        "max_users": 1,
        "max_projects": -1,  # unlimited
        "retention_days": 365,
        "max_memories": -1,  # unlimited
        "sdijap": True,
        "backup": True,
        "cifce": False,
        "compliance": False,
        "inheritance": True,
        "sso": False,
        "on_premise": False,
        "price_monthly": 9.99,
        "price_annual": 7.99,
    },
    "enterprise": {
        "max_users": 10,
        "max_projects": -1,
        "retention_days": -1,  # unlimited
        "max_memories": -1,
        "sdijap": True,
        "backup": True,
        "cifce": True,
        "compliance": True,
        "inheritance": True,
        "sso": True,
        "on_premise": False,
        "price_monthly": 19.99,
        "price_annual": 15.99,
    },
    "enterprise_team": {
        "max_users": 50,
        "max_projects": -1,
        "retention_days": -1,
        "max_memories": -1,
        "sdijap": True,
        "backup": True,
        "cifce": True,
        "compliance": True,
        "inheritance": True,
        "sso": True,
        "on_premise": True,
        "price_monthly": 79.99,
        "price_annual": 63.99,
    },
    "enterprise_custom": {
        "max_users": -1,  # unlimited
        "max_projects": -1,
        "retention_days": -1,
        "max_memories": -1,
        "sdijap": True,
        "backup": True,
        "cifce": True,
        "compliance": True,
        "inheritance": True,
        "sso": True,
        "on_premise": True,
        "price_monthly": -1,  # custom
        "price_annual": -1,
    },
}


def get_tier_limits() -> dict:
    """Get limits for the current tier."""
    tier = get_settings().tier
    return TIER_LIMITS.get(tier, TIER_LIMITS["free"])


def list_projects() -> list[dict]:
    """List all known SOAGILA projects with metadata."""
    projects_dir = get_soagila_home() / "projects"
    if not projects_dir.exists():
        return []

    projects = []
    for p in sorted(projects_dir.iterdir()):
        if not p.is_dir():
            continue
        meta_path = p / "project.json"
        db_path = p / "soagila.db"
        if meta_path.exists():
            try:
                meta = json.loads(meta_path.read_text(encoding="utf-8"))
                meta["hash"] = p.name
                meta["db_exists"] = db_path.exists()
                meta["db_size_kb"] = round(db_path.stat().st_size / 1024, 1) if db_path.exists() else 0
                projects.append(meta)
            except Exception as e:
                logger.warning(f"Failed to read project metadata {meta_path}: {e}")

    return projects


def get_current_project_info() -> dict:
    """Get metadata for the current project."""
    settings = get_settings()
    project_dir = get_project_dir()
    meta_path = project_dir / "project.json"
    db_path = project_dir / "soagila.db"

    info = {
        "cwd": settings.project_cwd,
        "hash": get_project_hash(),
        "name": Path(settings.project_cwd).name,
        "db_exists": db_path.exists(),
        "db_size_kb": round(db_path.stat().st_size / 1024, 1) if db_path.exists() else 0,
    }

    if meta_path.exists():
        try:
            meta = json.loads(meta_path.read_text(encoding="utf-8"))
            info["created_at"] = meta.get("created_at")
        except Exception:
            pass

    return info


def check_project_limit() -> tuple[bool, str]:
    """Check if the current tier allows creating/using this project.

    Returns (allowed, message).
    """
    limits = get_tier_limits()
    max_projects = limits["max_projects"]

    if max_projects == -1:
        return True, "Unlimited projects"

    existing = list_projects()
    current_hash = get_project_hash()

    # If this project already exists, always allow
    for p in existing:
        if p["hash"] == current_hash:
            return True, "Existing project"

    # Check if we've hit the limit
    if len(existing) >= max_projects:
        project_names = [p.get("name", p["hash"]) for p in existing]
        return False, (
            f"Free tier allows {max_projects} project(s). "
            f"Active: {', '.join(project_names)}. "
            f"Upgrade to Pro for unlimited projects: https://soagila.com/pricing"
        )

    return True, "Within limit"


async def check_memory_limit() -> tuple[bool, str]:
    """Check if the current project has hit its memory limit.

    Returns (allowed, message).
    """
    limits = get_tier_limits()
    max_memories = limits["max_memories"]

    if max_memories == -1:
        return True, "Unlimited memories"

    from soagila.db.sqlite_init import get_db
    db = await get_db()
    cursor = await db.execute("SELECT COUNT(*) FROM episodic_memories WHERE is_decayed = 0")
    count = (await cursor.fetchone())[0]

    if count >= max_memories:
        return False, (
            f"Free tier allows {max_memories} memories. "
            f"Current: {count}. "
            f"Upgrade to Pro for unlimited: https://soagila.com/pricing"
        )

    return True, f"{count}/{max_memories} memories used"


async def enforce_retention_limit():
    """Mark memories beyond retention limit as decayed.

    Free tier: 7 days, Pro: 365 days, Enterprise: unlimited.
    """
    limits = get_tier_limits()
    retention_days = limits["retention_days"]

    if retention_days == -1:
        return 0  # Unlimited retention

    from soagila.db.sqlite_init import get_db
    from datetime import timedelta

    cutoff = (datetime.now(timezone.utc) - timedelta(days=retention_days)).isoformat()

    db = await get_db()
    cursor = await db.execute(
        """UPDATE episodic_memories
           SET is_decayed = 1, updated_at = ?
           WHERE is_decayed = 0 AND created_at < ?""",
        (datetime.now(timezone.utc).isoformat(), cutoff),
    )
    await db.commit()

    expired = cursor.rowcount
    if expired > 0:
        logger.info(f"Retention enforcement: {expired} memories expired (>{retention_days} days)")
    return expired


def is_feature_allowed(feature: str) -> tuple[bool, str]:
    """Check if a feature is allowed for the current tier.

    Features: sdijap, cifce, compliance
    """
    limits = get_tier_limits()
    allowed = limits.get(feature, False)
    if not allowed:
        tier = get_settings().tier
        return False, f"{feature} requires Pro or Enterprise tier (current: {tier})"
    return True, "Allowed"
