"""
InsightFlow Phase 8 - 多租户 SaaS 架构管理模块

功能：
1. 租户隔离（数据、配置、资源完全隔离）
2. 自定义域名绑定（CNAME 支持）
3. 品牌白标（Logo、主题色、自定义 CSS）
4. 租户级权限管理

作者: InsightFlow Team
"""

import hashlib
import json
import logging
import re
import sqlite3
import uuid
from dataclasses import asdict, dataclass
from datetime import datetime
from enum import StrEnum
from typing import Any

logger = logging.getLogger(__name__)


class TenantLimits:
    """租户资源限制常量"""

    FREE_MAX_PROJECTS = 3
    FREE_MAX_STORAGE_MB = 100
    FREE_MAX_TRANSCRIPTION_MINUTES = 60
    FREE_MAX_API_CALLS_PER_DAY = 100
    FREE_MAX_TEAM_MEMBERS = 2
    FREE_MAX_ENTITIES = 100

    PRO_MAX_PROJECTS = 20
    PRO_MAX_STORAGE_MB = 1000
    PRO_MAX_TRANSCRIPTION_MINUTES = 600
    PRO_MAX_API_CALLS_PER_DAY = 10000
    PRO_MAX_TEAM_MEMBERS = 10
    PRO_MAX_ENTITIES = 1000

    UNLIMITED = -1


class TenantStatus(StrEnum):
    """租户状态"""

    ACTIVE = "active"  # 活跃
    SUSPENDED = "suspended"  # 暂停
    TRIAL = "trial"  # 试用
    EXPIRED = "expired"  # 过期
    PENDING = "pending"  # 待激活


class TenantTier(StrEnum):
    """租户订阅层级"""

    FREE = "free"  # 免费版
    PRO = "pro"  # 专业版
    ENTERPRISE = "enterprise"  # 企业版


class TenantRole(StrEnum):
    """租户角色"""

    OWNER = "owner"  # 所有者
    ADMIN = "admin"  # 管理员
    MEMBER = "member"  # 成员
    VIEWER = "viewer"  # 查看者


class DomainStatus(StrEnum):
    """域名状态"""

    PENDING = "pending"  # 待验证
    VERIFIED = "verified"  # 已验证
    FAILED = "failed"  # 验证失败
    EXPIRED = "expired"  # 已过期


@dataclass
class Tenant:
    """租户数据类"""

    id: str
    name: str
    slug: str  # URL 友好的唯一标识
    description: str | None
    tier: str  # free/pro/enterprise
    status: str  # active/suspended/trial/expired/pending
    owner_id: str  # 所有者用户ID
    created_at: datetime
    updated_at: datetime
    expires_at: datetime | None  # 订阅过期时间
    settings: dict[str, Any]  # 租户级设置
    resource_limits: dict[str, Any]  # 资源限制
    metadata: dict[str, Any]  # 元数据


@dataclass
class TenantDomain:
    """租户域名数据类"""

    id: str
    tenant_id: str
    domain: str  # 自定义域名
    status: str  # pending/verified/failed/expired
    verification_token: str  # 验证令牌
    verification_method: str  # dns/file
    verified_at: datetime | None
    created_at: datetime
    updated_at: datetime
    is_primary: bool  # 是否主域名
    ssl_enabled: bool  # SSL 是否启用
    ssl_expires_at: datetime | None


@dataclass
class TenantBranding:
    """租户品牌配置数据类"""

    id: str
    tenant_id: str
    logo_url: str | None  # Logo URL
    favicon_url: str | None  # Favicon URL
    primary_color: str | None  # 主题主色
    secondary_color: str | None  # 主题次色
    custom_css: str | None  # 自定义 CSS
    custom_js: str | None  # 自定义 JS
    login_page_bg: str | None  # 登录页背景
    email_template: str | None  # 邮件模板
    created_at: datetime
    updated_at: datetime


@dataclass
class TenantMember:
    """租户成员数据类"""

    id: str
    tenant_id: str
    user_id: str
    email: str
    role: str  # owner/admin/member/viewer
    permissions: list[str]  # 具体权限列表
    invited_by: str | None  # 邀请者
    invited_at: datetime
    joined_at: datetime | None
    last_active_at: datetime | None
    status: str  # active/pending/suspended


@dataclass
class TenantPermission:
    """租户权限定义数据类"""

    id: str
    tenant_id: str
    name: str  # 权限名称
    code: str  # 权限代码
    description: str | None
    resource_type: str  # project/entity/api/etc
    actions: list[str]  # create/read/update/delete/etc
    conditions: dict | None  # 条件限制
    created_at: datetime


class TenantManager:
    """租户管理器 - 多租户 SaaS 架构核心"""

    # 默认资源限制配置 - 使用常量
    DEFAULT_LIMITS = {
        TenantTier.FREE: {
            "max_projects": TenantLimits.FREE_MAX_PROJECTS,
            "max_storage_mb": TenantLimits.FREE_MAX_STORAGE_MB,
            "max_transcription_minutes": TenantLimits.FREE_MAX_TRANSCRIPTION_MINUTES,
            "max_api_calls_per_day": TenantLimits.FREE_MAX_API_CALLS_PER_DAY,
            "max_team_members": TenantLimits.FREE_MAX_TEAM_MEMBERS,
            "max_entities": TenantLimits.FREE_MAX_ENTITIES,
            "features": ["basic_analysis", "export_png"],
        },
        TenantTier.PRO: {
            "max_projects": TenantLimits.PRO_MAX_PROJECTS,
            "max_storage_mb": TenantLimits.PRO_MAX_STORAGE_MB,
            "max_transcription_minutes": TenantLimits.PRO_MAX_TRANSCRIPTION_MINUTES,
            "max_api_calls_per_day": TenantLimits.PRO_MAX_API_CALLS_PER_DAY,
            "max_team_members": TenantLimits.PRO_MAX_TEAM_MEMBERS,
            "max_entities": TenantLimits.PRO_MAX_ENTITIES,
            "features": [
                "basic_analysis",
                "advanced_analysis",
                "export_all",
                "api_access",
                "webhooks",
                "collaboration",
            ],
        },
        TenantTier.ENTERPRISE: {
            "max_projects": TenantLimits.UNLIMITED,  # 无限制
            "max_storage_mb": TenantLimits.UNLIMITED,
            "max_transcription_minutes": TenantLimits.UNLIMITED,
            "max_api_calls_per_day": TenantLimits.UNLIMITED,
            "max_team_members": TenantLimits.UNLIMITED,
            "max_entities": TenantLimits.UNLIMITED,
            "features": ["all"],  # 所有功能
        },
    }

    # 角色权限映射
    ROLE_PERMISSIONS = {
        TenantRole.OWNER: [
            "tenant:*",
            "project:*",
            "member:*",
            "billing:*",
            "settings:*",
            "api:*",
            "export:*",
        ],
        TenantRole.ADMIN: [
            "tenant:read",
            "project:*",
            "member:*",
            "billing:read",
            "settings:*",
            "api:*",
            "export:*",
        ],
        TenantRole.MEMBER: [
            "tenant:read",
            "project:create",
            "project:read",
            "project:update",
            "member:read",
            "export:basic",
        ],
        TenantRole.VIEWER: ["tenant:read", "project:read", "member:read"],
    }

    # 权限名称映射
    PERMISSION_NAMES = {
        "tenant:*": "租户完全控制",
        "tenant:read": "查看租户信息",
        "project:*": "项目完全控制",
        "project:create": "创建项目",
        "project:read": "查看项目",
        "project:update": "编辑项目",
        "member:*": "成员完全控制",
        "member:read": "查看成员",
        "billing:*": "账单完全控制",
        "billing:read": "查看账单",
        "settings:*": "设置完全控制",
        "api:*": "API完全控制",
        "export:*": "导出完全控制",
        "export:basic": "基础导出",
    }

    def __init__(self, db_path: str = "insightflow.db"):
        self.db_path = db_path
        self._init_db()

    def _get_connection(self) -> sqlite3.Connection:
        """获取数据库连接"""
        conn = sqlite3.connect(self.db_path)
        conn.row_factory = sqlite3.Row
        return conn

    def _init_db(self) -> None:
        """初始化数据库表"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()

            # 租户主表
            cursor.execute("""
                CREATE TABLE IF NOT EXISTS tenants (
                    id TEXT PRIMARY KEY,
                    name TEXT NOT NULL,
                    slug TEXT UNIQUE NOT NULL,
                    description TEXT,
                    tier TEXT DEFAULT 'free',
                    status TEXT DEFAULT 'pending',
                    owner_id TEXT NOT NULL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    expires_at TIMESTAMP,
                    settings TEXT DEFAULT '{}',
                    resource_limits TEXT DEFAULT '{}',
                    metadata TEXT DEFAULT '{}'
                )
            """)

            # 租户域名表
            cursor.execute("""
                CREATE TABLE IF NOT EXISTS tenant_domains (
                    id TEXT PRIMARY KEY,
                    tenant_id TEXT NOT NULL,
                    domain TEXT UNIQUE NOT NULL,
                    status TEXT DEFAULT 'pending',
                    verification_token TEXT NOT NULL,
                    verification_method TEXT DEFAULT 'dns',
                    verified_at TIMESTAMP,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    is_primary INTEGER DEFAULT 0,
                    ssl_enabled INTEGER DEFAULT 0,
                    ssl_expires_at TIMESTAMP,
                    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
                )
            """)

            # 租户品牌配置表
            cursor.execute("""
                CREATE TABLE IF NOT EXISTS tenant_branding (
                    id TEXT PRIMARY KEY,
                    tenant_id TEXT UNIQUE NOT NULL,
                    logo_url TEXT,
                    favicon_url TEXT,
                    primary_color TEXT,
                    secondary_color TEXT,
                    custom_css TEXT,
                    custom_js TEXT,
                    login_page_bg TEXT,
                    email_template TEXT,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
                )
            """)

            # 租户成员表
            cursor.execute("""
                CREATE TABLE IF NOT EXISTS tenant_members (
                    id TEXT PRIMARY KEY,
                    tenant_id TEXT NOT NULL,
                    user_id TEXT,
                    email TEXT NOT NULL,
                    role TEXT DEFAULT 'member',
                    permissions TEXT DEFAULT '[]',
                    invited_by TEXT,
                    invited_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    joined_at TIMESTAMP,
                    last_active_at TIMESTAMP,
                    status TEXT DEFAULT 'pending',
                    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
                )
            """)

            # 租户权限定义表
            cursor.execute("""
                CREATE TABLE IF NOT EXISTS tenant_permissions (
                    id TEXT PRIMARY KEY,
                    tenant_id TEXT NOT NULL,
                    name TEXT NOT NULL,
                    code TEXT NOT NULL,
                    description TEXT,
                    resource_type TEXT NOT NULL,
                    actions TEXT NOT NULL,
                    conditions TEXT,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
                    UNIQUE(tenant_id, code)
                )
            """)

            # 租户资源使用统计表
            cursor.execute("""
                CREATE TABLE IF NOT EXISTS tenant_usage (
                    id TEXT PRIMARY KEY,
                    tenant_id TEXT NOT NULL,
                    date DATE NOT NULL,
                    storage_bytes INTEGER DEFAULT 0,
                    transcription_seconds INTEGER DEFAULT 0,
                    api_calls INTEGER DEFAULT 0,
                    projects_count INTEGER DEFAULT 0,
                    entities_count INTEGER DEFAULT 0,
                    members_count INTEGER DEFAULT 0,
                    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
                    UNIQUE(tenant_id, date)
                )
            """)

            # 创建索引
            cursor.execute("CREATE INDEX IF NOT EXISTS idx_tenants_slug ON tenants(slug)")
            cursor.execute("CREATE INDEX IF NOT EXISTS idx_tenants_owner ON tenants(owner_id)")
            cursor.execute("CREATE INDEX IF NOT EXISTS idx_tenants_status ON tenants(status)")
            cursor.execute(
                "CREATE INDEX IF NOT EXISTS idx_domains_tenant ON tenant_domains(tenant_id)"
            )
            cursor.execute(
                "CREATE INDEX IF NOT EXISTS idx_domains_domain ON tenant_domains(domain)"
            )
            cursor.execute(
                "CREATE INDEX IF NOT EXISTS idx_domains_status ON tenant_domains(status)"
            )
            cursor.execute(
                "CREATE INDEX IF NOT EXISTS idx_members_tenant ON tenant_members(tenant_id)"
            )
            cursor.execute("CREATE INDEX IF NOT EXISTS idx_members_user ON tenant_members(user_id)")
            cursor.execute("CREATE INDEX IF NOT EXISTS idx_usage_tenant ON tenant_usage(tenant_id)")
            cursor.execute("CREATE INDEX IF NOT EXISTS idx_usage_date ON tenant_usage(date)")

            conn.commit()
            logger.info("Tenant tables initialized successfully")

        except Exception as e:
            logger.error(f"Error initializing tenant tables: {e}")
            raise
        finally:
            conn.close()

    # ==================== 租户管理 ====================

    def create_tenant(
        self,
        name: str,
        owner_id: str,
        tier: str = "free",
        description: str | None = None,
        settings: dict | None = None,
    ) -> Tenant:
        """创建新租户"""
        conn = self._get_connection()
        try:
            tenant_id = str(uuid.uuid4())
            slug = self._generate_slug(name)

            # 获取对应层级的资源限制
            tier_enum = (
                TenantTier(tier) if tier in [t.value for t in TenantTier] else TenantTier.FREE
            )
            resource_limits = self.DEFAULT_LIMITS.get(
                tier_enum, self.DEFAULT_LIMITS[TenantTier.FREE]
            )

            tenant = Tenant(
                id=tenant_id,
                name=name,
                slug=slug,
                description=description,
                tier=tier,
                status=TenantStatus.PENDING.value,
                owner_id=owner_id,
                created_at=datetime.now(),
                updated_at=datetime.now(),
                expires_at=None,
                settings=settings or {},
                resource_limits=resource_limits,
                metadata={},
            )

            cursor = conn.cursor()
            cursor.execute(
                """
                INSERT INTO tenants (id, name, slug, description, tier, status, owner_id,
                                   created_at, updated_at, expires_at, settings, resource_limits, metadata)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            """,
                (
                    tenant.id,
                    tenant.name,
                    tenant.slug,
                    tenant.description,
                    tenant.tier,
                    tenant.status,
                    tenant.owner_id,
                    tenant.created_at,
                    tenant.updated_at,
                    tenant.expires_at,
                    json.dumps(tenant.settings),
                    json.dumps(tenant.resource_limits),
                    json.dumps(tenant.metadata),
                ),
            )

            # 自动将所有者添加为成员
            self._add_member_internal(conn, tenant_id, owner_id, "", TenantRole.OWNER, None)

            conn.commit()
            logger.info(f"Tenant created: {tenant_id} ({name})")
            return tenant

        except Exception as e:
            conn.rollback()
            logger.error(f"Error creating tenant: {e}")
            raise
        finally:
            conn.close()

    def get_tenant(self, tenant_id: str) -> Tenant | None:
        """获取租户信息"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute("SELECT * FROM tenants WHERE id = ?", (tenant_id,))
            row = cursor.fetchone()

            if row:
                return self._row_to_tenant(row)
            return None

        finally:
            conn.close()

    def get_tenant_by_slug(self, slug: str) -> Tenant | None:
        """通过 slug 获取租户"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute("SELECT * FROM tenants WHERE slug = ?", (slug,))
            row = cursor.fetchone()

            if row:
                return self._row_to_tenant(row)
            return None

        finally:
            conn.close()

    def get_tenant_by_domain(self, domain: str) -> Tenant | None:
        """通过自定义域名获取租户"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute(
                """
                SELECT t.* FROM tenants t
                JOIN tenant_domains d ON t.id = d.tenant_id
                WHERE d.domain = ? AND d.status = 'verified'
            """,
                (domain,),
            )
            row = cursor.fetchone()

            if row:
                return self._row_to_tenant(row)
            return None

        finally:
            conn.close()

    def update_tenant(
        self,
        tenant_id: str,
        name: str | None = None,
        description: str | None = None,
        tier: str | None = None,
        status: str | None = None,
        settings: dict | None = None,
    ) -> Tenant | None:
        """更新租户信息"""
        conn = self._get_connection()
        try:
            tenant = self.get_tenant(tenant_id)
            if not tenant:
                return None

            updates = []
            params = []

            if name is not None:
                updates.append("name = ?")
                params.append(name)
            if description is not None:
                updates.append("description = ?")
                params.append(description)
            if tier is not None:
                updates.append("tier = ?")
                params.append(tier)
                # 更新资源限制
                tier_enum = TenantTier(tier)
                updates.append("resource_limits = ?")
                params.append(json.dumps(self.DEFAULT_LIMITS.get(tier_enum, {})))
            if status is not None:
                updates.append("status = ?")
                params.append(status)
            if settings is not None:
                updates.append("settings = ?")
                params.append(json.dumps(settings))

            updates.append("updated_at = ?")
            params.append(datetime.now())
            params.append(tenant_id)

            cursor = conn.cursor()
            cursor.execute(
                f"""
                UPDATE tenants SET {", ".join(updates)}
                WHERE id = ?
            """,
                params,
            )

            conn.commit()
            return self.get_tenant(tenant_id)

        finally:
            conn.close()

    def delete_tenant(self, tenant_id: str) -> bool:
        """删除租户（软删除或硬删除）"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute("DELETE FROM tenants WHERE id = ?", (tenant_id,))
            conn.commit()
            return cursor.rowcount > 0
        finally:
            conn.close()

    def list_tenants(
        self, status: str | None = None, tier: str | None = None, limit: int = 100, offset: int = 0
    ) -> list[Tenant]:
        """列出租户"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()

            query = "SELECT * FROM tenants WHERE 1=1"
            params = []

            if status:
                query += " AND status = ?"
                params.append(status)
            if tier:
                query += " AND tier = ?"
                params.append(tier)

            query += " ORDER BY created_at DESC LIMIT ? OFFSET ?"
            params.extend([limit, offset])

            cursor.execute(query, params)
            rows = cursor.fetchall()

            return [self._row_to_tenant(row) for row in rows]

        finally:
            conn.close()

    # ==================== 域名管理 ====================

    def add_domain(
        self,
        tenant_id: str,
        domain: str,
        is_primary: bool = False,
        verification_method: str = "dns",
    ) -> TenantDomain:
        """为租户添加自定义域名"""
        conn = self._get_connection()
        try:
            # 验证域名格式
            if not self._validate_domain(domain):
                raise ValueError(f"Invalid domain format: {domain}")

            # 生成验证令牌
            verification_token = self._generate_verification_token(tenant_id, domain)

            domain_id = str(uuid.uuid4())
            tenant_domain = TenantDomain(
                id=domain_id,
                tenant_id=tenant_id,
                domain=domain.lower(),
                status=DomainStatus.PENDING.value,
                verification_token=verification_token,
                verification_method=verification_method,
                verified_at=None,
                created_at=datetime.now(),
                updated_at=datetime.now(),
                is_primary=is_primary,
                ssl_enabled=False,
                ssl_expires_at=None,
            )

            cursor = conn.cursor()

            # 如果设为主域名，取消其他主域名
            if is_primary:
                cursor.execute(
                    """
                    UPDATE tenant_domains SET is_primary = 0
                    WHERE tenant_id = ?
                """,
                    (tenant_id,),
                )

            cursor.execute(
                """
                INSERT INTO tenant_domains (id, tenant_id, domain, status,
                    verification_token, verification_method, verified_at,
                    created_at, updated_at, is_primary, ssl_enabled, ssl_expires_at)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            """,
                (
                    tenant_domain.id,
                    tenant_domain.tenant_id,
                    tenant_domain.domain,
                    tenant_domain.status,
                    tenant_domain.verification_token,
                    tenant_domain.verification_method,
                    tenant_domain.verified_at,
                    tenant_domain.created_at,
                    tenant_domain.updated_at,
                    int(tenant_domain.is_primary),
                    int(tenant_domain.ssl_enabled),
                    tenant_domain.ssl_expires_at,
                ),
            )

            conn.commit()
            logger.info(f"Domain added: {domain} for tenant {tenant_id}")
            return tenant_domain

        except Exception as e:
            conn.rollback()
            logger.error(f"Error adding domain: {e}")
            raise
        finally:
            conn.close()

    def verify_domain(self, tenant_id: str, domain_id: str) -> bool:
        """验证域名所有权"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()

            # 获取域名信息
            cursor.execute(
                """
                SELECT * FROM tenant_domains
                WHERE id = ? AND tenant_id = ?
            """,
                (domain_id, tenant_id),
            )
            row = cursor.fetchone()

            if not row:
                return False

            domain = row["domain"]
            token = row["verification_token"]
            method = row["verification_method"]

            # 执行验证
            is_verified = self._check_domain_verification(domain, token, method)

            if is_verified:
                cursor.execute(
                    """
                    UPDATE tenant_domains
                    SET status = 'verified', verified_at = ?, updated_at = ?
                    WHERE id = ?
                """,
                    (datetime.now(), datetime.now(), domain_id),
                )
                conn.commit()
                logger.info(f"Domain verified: {domain}")
            else:
                cursor.execute(
                    """
                    UPDATE tenant_domains
                    SET status = 'failed', updated_at = ?
                    WHERE id = ?
                """,
                    (datetime.now(), domain_id),
                )
                conn.commit()

            return is_verified

        except Exception as e:
            logger.error(f"Error verifying domain: {e}")
            return False
        finally:
            conn.close()

    def get_domain_verification_instructions(self, domain_id: str) -> dict[str, Any]:
        """获取域名验证指导"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute("SELECT * FROM tenant_domains WHERE id = ?", (domain_id,))
            row = cursor.fetchone()

            if not row:
                return None

            domain = row["domain"]
            token = row["verification_token"]

            return {
                "domain": domain,
                "verification_method": row["verification_method"],
                "dns_record": {
                    "type": "TXT",
                    "name": "_insightflow",
                    "value": f"insightflow-verify={token}",
                    "ttl": 3600,
                },
                "file_verification": {
                    "url": f"http://{domain}/.well-known/insightflow-verify.txt",
                    "content": token,
                },
                "instructions": [
                    f"DNS 验证: 添加 TXT 记录 _insightflow.{domain}，值为 insightflow-verify={token}",
                    f"文件验证: 在网站根目录创建 .well-known/insightflow-verify.txt，内容为 {token}",
                ],
            }

        finally:
            conn.close()

    def remove_domain(self, tenant_id: str, domain_id: str) -> bool:
        """移除域名绑定"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute(
                """
                DELETE FROM tenant_domains
                WHERE id = ? AND tenant_id = ?
            """,
                (domain_id, tenant_id),
            )
            conn.commit()
            return cursor.rowcount > 0
        finally:
            conn.close()

    def list_domains(self, tenant_id: str) -> list[TenantDomain]:
        """列出租户的所有域名"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute(
                """
                SELECT * FROM tenant_domains
                WHERE tenant_id = ?
                ORDER BY is_primary DESC, created_at DESC
            """,
                (tenant_id,),
            )
            rows = cursor.fetchall()

            return [self._row_to_domain(row) for row in rows]

        finally:
            conn.close()

    # ==================== 品牌白标管理 ====================

    def get_branding(self, tenant_id: str) -> TenantBranding | None:
        """获取租户品牌配置"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute("SELECT * FROM tenant_branding WHERE tenant_id = ?", (tenant_id,))
            row = cursor.fetchone()

            if row:
                return self._row_to_branding(row)
            return None

        finally:
            conn.close()

    def update_branding(
        self,
        tenant_id: str,
        logo_url: str | None = None,
        favicon_url: str | None = None,
        primary_color: str | None = None,
        secondary_color: str | None = None,
        custom_css: str | None = None,
        custom_js: str | None = None,
        login_page_bg: str | None = None,
        email_template: str | None = None,
    ) -> TenantBranding:
        """更新租户品牌配置"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()

            # 检查是否已存在
            cursor.execute("SELECT id FROM tenant_branding WHERE tenant_id = ?", (tenant_id,))
            existing = cursor.fetchone()

            if existing:
                # 更新
                updates = []
                params = []

                if logo_url is not None:
                    updates.append("logo_url = ?")
                    params.append(logo_url)
                if favicon_url is not None:
                    updates.append("favicon_url = ?")
                    params.append(favicon_url)
                if primary_color is not None:
                    updates.append("primary_color = ?")
                    params.append(primary_color)
                if secondary_color is not None:
                    updates.append("secondary_color = ?")
                    params.append(secondary_color)
                if custom_css is not None:
                    updates.append("custom_css = ?")
                    params.append(custom_css)
                if custom_js is not None:
                    updates.append("custom_js = ?")
                    params.append(custom_js)
                if login_page_bg is not None:
                    updates.append("login_page_bg = ?")
                    params.append(login_page_bg)
                if email_template is not None:
                    updates.append("email_template = ?")
                    params.append(email_template)

                updates.append("updated_at = ?")
                params.append(datetime.now())
                params.append(tenant_id)

                cursor.execute(
                    f"""
                    UPDATE tenant_branding SET {", ".join(updates)}
                    WHERE tenant_id = ?
                """,
                    params,
                )
            else:
                # 创建
                branding_id = str(uuid.uuid4())
                cursor.execute(
                    """
                    INSERT INTO tenant_branding
                    (id, tenant_id, logo_url, favicon_url, primary_color, secondary_color,
                     custom_css, custom_js, login_page_bg, email_template, created_at, updated_at)
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                """,
                    (
                        branding_id,
                        tenant_id,
                        logo_url,
                        favicon_url,
                        primary_color,
                        secondary_color,
                        custom_css,
                        custom_js,
                        login_page_bg,
                        email_template,
                        datetime.now(),
                        datetime.now(),
                    ),
                )

            conn.commit()
            return self.get_branding(tenant_id)

        finally:
            conn.close()

    def get_branding_css(self, tenant_id: str) -> str:
        """生成品牌 CSS"""
        branding = self.get_branding(tenant_id)
        if not branding:
            return ""

        css = []

        if branding.primary_color:
            css.append(f"""
                :root {{
                    --tenant-primary: {branding.primary_color};
                    --tenant-primary-hover: {self._darken_color(branding.primary_color, 10)};
                }}
                .tenant-primary {{ color: var(--tenant-primary) !important; }}
                .tenant-bg-primary {{ background-color: var(--tenant-primary) !important; }}
                .tenant-btn-primary {{
                    background-color: var(--tenant-primary) !important;
                    border-color: var(--tenant-primary) !important;
                }}
                .tenant-btn-primary:hover {{
                    background-color: var(--tenant-primary-hover) !important;
                    border-color: var(--tenant-primary-hover) !important;
                }}
            """)

        if branding.secondary_color:
            css.append(f"""
                :root {{ --tenant-secondary: {branding.secondary_color}; }}
                .tenant-secondary {{ color: var(--tenant-secondary) !important; }}
                .tenant-bg-secondary {{ background-color: var(--tenant-secondary) !important; }}
            """)

        if branding.custom_css:
            css.append(branding.custom_css)

        return "\n".join(css)

    # ==================== 成员与权限管理 ====================

    def invite_member(
        self,
        tenant_id: str,
        email: str,
        role: str,
        invited_by: str,
        permissions: list[str] | None = None,
    ) -> TenantMember:
        """邀请成员加入租户"""
        conn = self._get_connection()
        try:
            member_id = str(uuid.uuid4())

            # 使用角色默认权限
            role_enum = (
                TenantRole(role) if role in [r.value for r in TenantRole] else TenantRole.MEMBER
            )
            default_permissions = self.ROLE_PERMISSIONS.get(role_enum, [])
            final_permissions = permissions or default_permissions

            member = TenantMember(
                id=member_id,
                tenant_id=tenant_id,
                user_id="pending",  # 临时值，待用户接受邀请后更新
                email=email,
                role=role,
                permissions=final_permissions,
                invited_by=invited_by,
                invited_at=datetime.now(),
                joined_at=None,
                last_active_at=None,
                status="pending",
            )

            cursor = conn.cursor()
            cursor.execute(
                """
                INSERT INTO tenant_members
                (id, tenant_id, user_id, email, role, permissions, invited_by,
                 invited_at, joined_at, last_active_at, status)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            """,
                (
                    member.id,
                    member.tenant_id,
                    member.user_id,
                    member.email,
                    member.role,
                    json.dumps(member.permissions),
                    member.invited_by,
                    member.invited_at,
                    member.joined_at,
                    member.last_active_at,
                    member.status,
                ),
            )

            conn.commit()
            logger.info(f"Member invited: {email} to tenant {tenant_id}")
            return member

        finally:
            conn.close()

    def accept_invitation(self, invitation_id: str, user_id: str) -> bool:
        """接受邀请"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute(
                """
                UPDATE tenant_members
                SET user_id = ?, status = 'active', joined_at = ?
                WHERE id = ? AND status = 'pending'
            """,
                (user_id, datetime.now(), invitation_id),
            )

            conn.commit()
            return cursor.rowcount > 0

        finally:
            conn.close()

    def remove_member(self, tenant_id: str, member_id: str) -> bool:
        """移除成员"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute(
                """
                DELETE FROM tenant_members
                WHERE id = ? AND tenant_id = ?
            """,
                (member_id, tenant_id),
            )
            conn.commit()
            return cursor.rowcount > 0
        finally:
            conn.close()

    def update_member_role(
        self, tenant_id: str, member_id: str, role: str, permissions: list[str] | None = None
    ) -> bool:
        """更新成员角色"""
        conn = self._get_connection()
        try:
            role_enum = TenantRole(role)
            default_permissions = self.ROLE_PERMISSIONS.get(role_enum, [])
            final_permissions = permissions or default_permissions

            cursor = conn.cursor()
            cursor.execute(
                """
                UPDATE tenant_members
                SET role = ?, permissions = ?, updated_at = ?
                WHERE id = ? AND tenant_id = ?
            """,
                (role, json.dumps(final_permissions), datetime.now(), member_id, tenant_id),
            )

            conn.commit()
            return cursor.rowcount > 0

        finally:
            conn.close()

    def list_members(self, tenant_id: str, status: str | None = None) -> list[TenantMember]:
        """列出租户成员"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()

            query = "SELECT * FROM tenant_members WHERE tenant_id = ?"
            params = [tenant_id]

            if status:
                query += " AND status = ?"
                params.append(status)

            query += " ORDER BY invited_at DESC"

            cursor.execute(query, params)
            rows = cursor.fetchall()

            return [self._row_to_member(row) for row in rows]

        finally:
            conn.close()

    def check_permission(self, tenant_id: str, user_id: str, resource: str, action: str) -> bool:
        """检查用户是否有特定权限"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute(
                """
                SELECT role, permissions FROM tenant_members
                WHERE tenant_id = ? AND user_id = ? AND status = 'active'
            """,
                (tenant_id, user_id),
            )
            row = cursor.fetchone()

            if not row:
                return False

            role = row["role"]
            permissions = json.loads(row["permissions"] or "[]")

            # 所有者拥有所有权限
            if role == TenantRole.OWNER.value:
                return True

            # 检查具体权限
            required = f"{resource}:{action}"
            wildcard = f"{resource}:*"

            return required in permissions or wildcard in permissions or "*" in permissions

        finally:
            conn.close()

    def get_user_tenants(self, user_id: str) -> list[dict[str, Any]]:
        """获取用户所属的所有租户"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute(
                """
                SELECT t.*, m.role, m.status as member_status
                FROM tenants t
                JOIN tenant_members m ON t.id = m.tenant_id
                WHERE m.user_id = ? AND m.status = 'active'
                ORDER BY t.created_at DESC
            """,
                (user_id,),
            )
            rows = cursor.fetchall()

            result = []
            for row in rows:
                tenant = self._row_to_tenant(row)
                result.append(
                    {
                        **asdict(tenant),
                        "member_role": row["role"],
                        "member_status": row["member_status"],
                    }
                )
            return result

        finally:
            conn.close()

    # ==================== 资源使用统计 ====================

    def record_usage(
        self,
        tenant_id: str,
        storage_bytes: int = 0,
        transcription_seconds: int = 0,
        api_calls: int = 0,
        projects_count: int = 0,
        entities_count: int = 0,
        members_count: int = 0,
    ):
        """记录资源使用"""
        conn = self._get_connection()
        try:
            today = datetime.now().date()
            usage_id = str(uuid.uuid4())

            cursor = conn.cursor()
            cursor.execute(
                """
                INSERT INTO tenant_usage
                (id, tenant_id, date, storage_bytes, transcription_seconds, api_calls,
                 projects_count, entities_count, members_count)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
                ON CONFLICT(tenant_id, date) DO UPDATE SET
                    storage_bytes = storage_bytes + excluded.storage_bytes,
                    transcription_seconds = transcription_seconds + excluded.transcription_seconds,
                    api_calls = api_calls + excluded.api_calls,
                    projects_count = MAX(projects_count, excluded.projects_count),
                    entities_count = MAX(entities_count, excluded.entities_count),
                    members_count = MAX(members_count, excluded.members_count)
            """,
                (
                    usage_id,
                    tenant_id,
                    today,
                    storage_bytes,
                    transcription_seconds,
                    api_calls,
                    projects_count,
                    entities_count,
                    members_count,
                ),
            )

            conn.commit()

        finally:
            conn.close()

    def get_usage_stats(
        self, tenant_id: str, start_date: datetime | None = None, end_date: datetime | None = None
    ) -> dict[str, Any]:
        """获取使用统计"""
        conn = self._get_connection()
        try:
            cursor = conn.cursor()

            query = """
                SELECT
                    SUM(storage_bytes) as total_storage,
                    SUM(transcription_seconds) as total_transcription,
                    SUM(api_calls) as total_api_calls,
                    MAX(projects_count) as max_projects,
                    MAX(entities_count) as max_entities,
                    MAX(members_count) as max_members
                FROM tenant_usage
                WHERE tenant_id = ?
            """
            params = [tenant_id]

            if start_date:
                query += " AND date >= ?"
                params.append(start_date.date())
            if end_date:
                query += " AND date <= ?"
                params.append(end_date.date())

            cursor.execute(query, params)
            row = cursor.fetchone()

            # 获取租户限制
            tenant = self.get_tenant(tenant_id)
            limits = tenant.resource_limits if tenant else {}

            return {
                "storage_bytes": row["total_storage"] or 0,
                "storage_mb": (row["total_storage"] or 0) / (1024 * 1024),
                "transcription_seconds": row["total_transcription"] or 0,
                "transcription_minutes": (row["total_transcription"] or 0) / 60,
                "api_calls": row["total_api_calls"] or 0,
                "projects_count": row["max_projects"] or 0,
                "entities_count": row["max_entities"] or 0,
                "members_count": row["max_members"] or 0,
                "limits": limits,
                "usage_percentages": {
                    "storage": self._calc_percentage(
                        row["total_storage"] or 0, limits.get("max_storage_mb", 0) * 1024 * 1024
                    ),
                    "transcription": self._calc_percentage(
                        row["total_transcription"] or 0,
                        limits.get("max_transcription_minutes", 0) * 60,
                    ),
                    "api_calls": self._calc_percentage(
                        row["total_api_calls"] or 0, limits.get("max_api_calls_per_day", 0)
                    ),
                    "projects": self._calc_percentage(
                        row["max_projects"] or 0, limits.get("max_projects", 0)
                    ),
                    "entities": self._calc_percentage(
                        row["max_entities"] or 0, limits.get("max_entities", 0)
                    ),
                    "members": self._calc_percentage(
                        row["max_members"] or 0, limits.get("max_team_members", 0)
                    ),
                },
            }

        finally:
            conn.close()

    def check_resource_limit(self, tenant_id: str, resource_type: str) -> tuple[bool, int, int]:
        """检查资源是否超限

        Returns:
            (是否允许, 当前使用量, 限制值)
        """
        tenant = self.get_tenant(tenant_id)
        if not tenant:
            return False, 0, 0

        limits = tenant.resource_limits
        stats = self.get_usage_stats(tenant_id)

        resource_map = {
            "storage": ("storage_mb", stats["storage_mb"]),
            "transcription": ("max_transcription_minutes", stats["transcription_minutes"]),
            "api_calls": ("max_api_calls_per_day", stats["api_calls"]),
            "projects": ("max_projects", stats["projects_count"]),
            "entities": ("max_entities", stats["entities_count"]),
            "members": ("max_team_members", stats["members_count"]),
        }

        if resource_type not in resource_map:
            return True, 0, -1

        limit_key, current = resource_map[resource_type]
        limit = limits.get(limit_key, 0)

        # -1 表示无限制
        if limit == -1:
            return True, current, limit

        return current < limit, current, limit

    # ==================== 辅助方法 ====================

    def _generate_slug(self, name: str) -> str:
        """生成 URL 友好的 slug"""
        # 转换为小写，替换空格为连字符
        slug = re.sub(r"[^\w\s-]", "", name.lower())
        slug = re.sub(r"[-\s]+", "-", slug)

        # 检查是否已存在
        conn = self._get_connection()
        try:
            cursor = conn.cursor()
            base_slug = slug
            counter = 1

            while True:
                cursor.execute("SELECT id FROM tenants WHERE slug = ?", (slug,))
                if not cursor.fetchone():
                    break
                slug = f"{base_slug}-{counter}"
                counter += 1

            return slug

        finally:
            conn.close()

    def _generate_verification_token(self, tenant_id: str, domain: str) -> str:
        """生成域名验证令牌"""
        data = f"{tenant_id}:{domain}:{datetime.now().isoformat()}"
        return hashlib.sha256(data.encode()).hexdigest()[:32]

    def _validate_domain(self, domain: str) -> bool:
        """验证域名格式"""
        pattern = r"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)*[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])$"
        return bool(re.match(pattern, domain))

    def _check_domain_verification(self, domain: str, token: str, method: str) -> bool:
        """检查域名验证状态"""
        # 这里应该实现实际的 DNS 查询或 HTTP 请求
        # 简化实现：模拟验证成功
        # 实际部署时需要使用 dnspython 或 requests 进行真实验证

        if method == "dns":
            # TODO: 实现 DNS TXT 记录查询
            # import dns.resolver
            # try:
            #     answers = dns.resolver.resolve(f"_insightflow.{domain}", 'TXT')
            #     for rdata in answers:
            #         if token in str(rdata):
            #             return True
            # except (ImportError, Exception):
            #     pass
            return True  # 模拟成功

        elif method == "file":
            # TODO: 实现 HTTP 文件验证
            # import requests
            # try:
            #     response = requests.get(f"http://{domain}/.well-known/insightflow-verify.txt", timeout=10)
            #     if response.status_code == 200 and token in response.text:
            #         return True
            # except (ImportError, Exception):
            #     pass
            return True  # 模拟成功

        return False

    def _darken_color(self, hex_color: str, percent: int) -> str:
        """加深颜色"""
        hex_color = hex_color.lstrip("#")
        r = int(hex_color[0:2], 16)
        g = int(hex_color[2:4], 16)
        b = int(hex_color[4:6], 16)

        r = int(r * (100 - percent) / 100)
        g = int(g * (100 - percent) / 100)
        b = int(b * (100 - percent) / 100)

        return f"#{r:02x}{g:02x}{b:02x}"

    def _calc_percentage(self, current: int, limit: int) -> float:
        """计算使用百分比"""
        if limit <= 0:
            return 0.0 if limit == 0 else 100.0
        return min(100.0, round(current / limit * 100, 2))

    def _add_member_internal(
        self,
        conn: sqlite3.Connection,
        tenant_id: str,
        user_id: str,
        email: str,
        role: TenantRole,
        invited_by: str | None,
    ):
        """内部方法：添加成员"""
        cursor = conn.cursor()
        member_id = str(uuid.uuid4())

        cursor.execute(
            """
            INSERT OR IGNORE INTO tenant_members
            (id, tenant_id, user_id, email, role, permissions, invited_by,
             invited_at, joined_at, last_active_at, status)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        """,
            (
                member_id,
                tenant_id,
                user_id,
                email,
                role.value,
                json.dumps(self.ROLE_PERMISSIONS.get(role, [])),
                invited_by,
                datetime.now(),
                datetime.now(),
                datetime.now(),
                "active",
            ),
        )

    def _row_to_tenant(self, row: sqlite3.Row) -> Tenant:
        """数据库行转换为 Tenant 对象"""
        return Tenant(
            id=row["id"],
            name=row["name"],
            slug=row["slug"],
            description=row["description"],
            tier=row["tier"],
            status=row["status"],
            owner_id=row["owner_id"],
            created_at=(
                datetime.fromisoformat(row["created_at"])
                if isinstance(row["created_at"], str)
                else row["created_at"]
            ),
            updated_at=(
                datetime.fromisoformat(row["updated_at"])
                if isinstance(row["updated_at"], str)
                else row["updated_at"]
            ),
            expires_at=(
                datetime.fromisoformat(row["expires_at"])
                if row["expires_at"] and isinstance(row["expires_at"], str)
                else row["expires_at"]
            ),
            settings=json.loads(row["settings"] or "{}"),
            resource_limits=json.loads(row["resource_limits"] or "{}"),
            metadata=json.loads(row["metadata"] or "{}"),
        )

    def _row_to_domain(self, row: sqlite3.Row) -> TenantDomain:
        """数据库行转换为 TenantDomain 对象"""
        return TenantDomain(
            id=row["id"],
            tenant_id=row["tenant_id"],
            domain=row["domain"],
            status=row["status"],
            verification_token=row["verification_token"],
            verification_method=row["verification_method"],
            verified_at=(
                datetime.fromisoformat(row["verified_at"])
                if row["verified_at"] and isinstance(row["verified_at"], str)
                else row["verified_at"]
            ),
            created_at=(
                datetime.fromisoformat(row["created_at"])
                if isinstance(row["created_at"], str)
                else row["created_at"]
            ),
            updated_at=(
                datetime.fromisoformat(row["updated_at"])
                if isinstance(row["updated_at"], str)
                else row["updated_at"]
            ),
            is_primary=bool(row["is_primary"]),
            ssl_enabled=bool(row["ssl_enabled"]),
            ssl_expires_at=(
                datetime.fromisoformat(row["ssl_expires_at"])
                if row["ssl_expires_at"] and isinstance(row["ssl_expires_at"], str)
                else row["ssl_expires_at"]
            ),
        )

    def _row_to_branding(self, row: sqlite3.Row) -> TenantBranding:
        """数据库行转换为 TenantBranding 对象"""
        return TenantBranding(
            id=row["id"],
            tenant_id=row["tenant_id"],
            logo_url=row["logo_url"],
            favicon_url=row["favicon_url"],
            primary_color=row["primary_color"],
            secondary_color=row["secondary_color"],
            custom_css=row["custom_css"],
            custom_js=row["custom_js"],
            login_page_bg=row["login_page_bg"],
            email_template=row["email_template"],
            created_at=(
                datetime.fromisoformat(row["created_at"])
                if isinstance(row["created_at"], str)
                else row["created_at"]
            ),
            updated_at=(
                datetime.fromisoformat(row["updated_at"])
                if isinstance(row["updated_at"], str)
                else row["updated_at"]
            ),
        )

    def _row_to_member(self, row: sqlite3.Row) -> TenantMember:
        """数据库行转换为 TenantMember 对象"""
        return TenantMember(
            id=row["id"],
            tenant_id=row["tenant_id"],
            user_id=row["user_id"],
            email=row["email"],
            role=row["role"],
            permissions=json.loads(row["permissions"] or "[]"),
            invited_by=row["invited_by"],
            invited_at=(
                datetime.fromisoformat(row["invited_at"])
                if isinstance(row["invited_at"], str)
                else row["invited_at"]
            ),
            joined_at=(
                datetime.fromisoformat(row["joined_at"])
                if row["joined_at"] and isinstance(row["joined_at"], str)
                else row["joined_at"]
            ),
            last_active_at=(
                datetime.fromisoformat(row["last_active_at"])
                if row["last_active_at"] and isinstance(row["last_active_at"], str)
                else row["last_active_at"]
            ),
            status=row["status"],
        )


# ==================== 租户上下文管理 ====================


class TenantContext:
    """租户上下文管理器 - 用于请求级别的租户隔离"""

    _current_tenant_id: str | None = None
    _current_user_id: str | None = None

    @classmethod
    def set_current_tenant(cls, tenant_id: str) -> None:
        """设置当前租户上下文"""
        cls._current_tenant_id = tenant_id

    @classmethod
    def get_current_tenant(cls) -> str | None:
        """获取当前租户ID"""
        return cls._current_tenant_id

    @classmethod
    def set_current_user(cls, user_id: str) -> None:
        """设置当前用户"""
        cls._current_user_id = user_id

    @classmethod
    def get_current_user(cls) -> str | None:
        """获取当前用户ID"""
        return cls._current_user_id

    @classmethod
    def clear(cls) -> None:
        """清除上下文"""
        cls._current_tenant_id = None
        cls._current_user_id = None


# 全局租户管理器实例
tenant_manager = None


def get_tenant_manager(db_path: str = "insightflow.db") -> TenantManager:
    """获取租户管理器实例（单例模式）"""
    global tenant_manager
    if tenant_manager is None:
        tenant_manager = TenantManager(db_path)
    return tenant_manager
