import os
from pathlib import Path

from apps.core.utils.djacore import apply_service_limits
from django.conf import settings
from django.db.models import Q


def autoload_user_apps():
    """基于 settings.BASE_DIR 自动扫描用户应用，根据服务状态限制数量"""
    user_apps = []
    base_dir = os.path.join(settings.BASE_DIR, "user_space")
    apps_dir = os.path.join(base_dir, "apps")
    os.makedirs(apps_dir, mode=0o755, exist_ok=True)

    if not os.access(apps_dir, os.W_OK):
        raise PermissionError(f"目录 {apps_dir} 不可写，请检查权限！")

    # 扫描所有符合条件的应用
    for app_name in os.listdir(apps_dir):
        app_path = os.path.join(apps_dir, app_name)
        if (
            os.path.isdir(app_path)
            and os.path.exists(os.path.join(app_path, "__init__.py"))
            and os.path.exists(os.path.join(app_path, "apps.py"))
        ):
            user_apps.append(f"user_space.apps.{app_name}")

    # 根据服务状态应用限制
    return apply_service_limits(user_apps)


def read_dependencies(app_dir):
    """读取应用的依赖声明文件"""
    deps_files = [
        app_dir / "dependencies.txt",
        # app_dir / "requirements.txt",
        # app_dir / "installed_apps.txt"  # 多种可能的文件名
    ]

    dependencies = []

    for deps_file in deps_files:
        if deps_file.exists():
            try:
                with open(deps_file, "r", encoding="utf-8") as f:
                    for line in f:
                        line = line.strip()
                        # 跳过空行和注释
                        if line and not line.startswith("#"):
                            dependencies.append(line)
            except Exception as e:
                print(f"Warning: Failed to read dependencies from {deps_file}: {e}")
            break  # 只读取第一个找到的文件

    return dependencies


def settings_autoload_user_apps():
    """自动扫描并注册用户应用及其模板目录和依赖"""
    BASE_DIR = Path(settings.BASE_DIR) / "user_space"
    USER_APPS_DIR = BASE_DIR / "apps"

    # 确保目录存在
    USER_APPS_DIR.mkdir(mode=0o755, parents=True, exist_ok=True)

    user_apps = []
    template_dirs = []
    app_dependencies = {}  # 应用名 -> 依赖列表

    # 第一步：扫描所有应用，收集依赖
    for app_dir in USER_APPS_DIR.iterdir():
        if (
            app_dir.is_dir()
            and (app_dir / "__init__.py").exists()
            and (app_dir / "apps.py").exists()
        ):
            app_name = f"user_space.apps.{app_dir.name}"
            user_apps.append(app_name)

            # 读取应用的依赖声明
            dependencies = read_dependencies(app_dir)
            if dependencies:
                app_dependencies[app_name] = dependencies

            # 添加模板目录
            templates_path = app_dir / "templates"
            if templates_path.exists():
                template_dirs.append(str(templates_path))

    # 第二步：应用服务限制
    limited_apps = apply_service_limits(user_apps)

    # 第三步：收集被限制应用的依赖
    all_dependencies = set()
    for app_name in limited_apps:
        if app_name in app_dependencies:
            all_dependencies.update(app_dependencies[app_name])

    # 第四步：合并返回（依赖 + 应用本身）
    # 注意：依赖放在前面，确保先加载
    result_apps = list(all_dependencies) + limited_apps

    # 第五步：限制模板目录
    if len(limited_apps) < len(user_apps):
        limited_template_dirs = []
        for app_name in limited_apps:
            app_dir_name = app_name.split(".")[-1]
            templates_path = USER_APPS_DIR / app_dir_name / "templates"
            if templates_path.exists():
                limited_template_dirs.append(str(templates_path))
        template_dirs = limited_template_dirs

    return result_apps, template_dirs


def get_contenttype_choices():
    """
    生成ContentType的limit_choices_to查询条件
    :param include_user_space: 是否包含user_space下的模型
    :return: Q对象构成的查询条件
    """
    include_user_space = True

    def extract_app_labels(app_paths):
        return [path.split(".")[-1] for path in app_paths]

    base_conditions = Q(app_label="content")
    exclude_models = [
        "tag",
        "category",
        "platformdownload",
        "contentmanager",
        "cutword",
        "searchhistory",
    ]

    if include_user_space:
        user_apps = extract_app_labels(autoload_user_apps())
        base_conditions |= Q(app_label__in=user_apps)

    return base_conditions & ~Q(model__in=exclude_models)
