"""
PostgreSQL Dashboard Data Access Layer

This module provides all database operations for the dashboard functionality
using PostgreSQL with asyncpg for high performance async operations.
"""
from __future__ import annotations

import calendar
import hashlib
import hmac
import json
import os
import secrets
import time
import uuid
from datetime import datetime, timedelta, timezone
from typing import Any, Dict, List, Optional
from uuid import UUID

from app.auth.api_keys import Plan, PLAN_CONFIGS
from app.dashboard.models import (
    ActivityItem,
    AnalyticsResponse,
    ApiKeyResponse,
    ApiKeyWithSecret,
    BillingPlan,
    DashboardStats,
    IndustryType,
    CompanySize,
    NotificationSettings,
    OrganizationResponse,
    PaymentMethod,
    SecuritySettings,
    SubscriptionResponse,
    TeamMember,
    TimeSeriesDataPoint,
    UserProfile,
    UserRole,
    UserSettings,
    UsageAnalytics,
    UsageStats,
)
from app.observability.logging import get_logger
from app.storage.database import get_connection, get_transaction

_logger = get_logger("dashboard.data")


def _normalize_billing_interval(value: Optional[str]) -> str:
    if value in ("month", "year"):
        return value
    return os.getenv("DEFAULT_BILLING_INTERVAL", "month")


def _add_billing_interval(start: datetime, interval: str) -> datetime:
    if interval == "year":
        year = start.year + 1
        last_day = calendar.monthrange(year, start.month)[1]
        return start.replace(year=year, day=min(start.day, last_day))
    year = start.year + (start.month // 12)
    month = start.month % 12 + 1
    last_day = calendar.monthrange(year, month)[1]
    return start.replace(year=year, month=month, day=min(start.day, last_day))


async def _create_subscription(
    conn,
    org_id: UUID,
    plan: str,
    billing_interval: str,
) -> dict:
    now = datetime.now(timezone.utc)
    normalized_interval = _normalize_billing_interval(billing_interval)
    period_end = _add_billing_interval(now, normalized_interval)
    row = await conn.fetchrow(
        """
        INSERT INTO subscriptions (
            organization_id,
            plan,
            status,
            billing_interval,
            current_period_start,
            current_period_end,
            cancel_at_period_end
        )
        VALUES ($1, $2, 'active', $3, $4, $5, FALSE)
        RETURNING id, organization_id, plan, status, billing_interval,
                  current_period_start, current_period_end, cancel_at_period_end,
                  created_at, updated_at
        """,
        org_id,
        plan,
        normalized_interval,
        now,
        period_end,
    )
    return dict(row) if row else {}


class DataAccessError(Exception):
    pass


class UserNotFoundError(DataAccessError):
    pass


class OrganizationNotFoundError(DataAccessError):
    pass


class ApiKeyNotFoundError(DataAccessError):
    pass


# =============================================================================
# User Operations
# =============================================================================

async def create_user(
    email: str,
    password_hash: str,
    first_name: str,
    last_name: str
) -> str:
    """Create a new user and return user ID."""
    async with get_connection() as conn:
        user_id = await conn.fetchval("""
            INSERT INTO users (email, password_hash, first_name, last_name, role)
            VALUES ($1, $2, $3, $4, 'owner')
            RETURNING id
        """, email.lower(), password_hash, first_name, last_name)
        
        _logger.info(f"Created user {user_id} with email {email}")
        return str(user_id)


async def get_user_by_email(email: str) -> Optional[Dict[str, Any]]:
    """Get user by email address."""
    async with get_connection() as conn:
        row = await conn.fetchrow("""
            SELECT id, email, password_hash, first_name, last_name, role,
                   organization_id, avatar_url, is_active, last_login_at,
                   created_at, updated_at
            FROM users 
            WHERE email = $1 AND is_active = true
        """, email.lower())
        
        if row:
            return {
                "id": str(row["id"]),
                "email": row["email"],
                "password_hash": row["password_hash"],
                "first_name": row["first_name"],
                "last_name": row["last_name"],
                "role": row["role"],
                "organization_id": str(row["organization_id"]) if row["organization_id"] else None,
                "avatar_url": row["avatar_url"],
                "is_active": row["is_active"],
                "last_login": row["last_login_at"],
                "created_at": row["created_at"],
                "updated_at": row["updated_at"]
            }
        return None


async def get_user_by_id(user_id: str) -> Optional[Dict[str, Any]]:
    """Get user by ID."""
    async with get_connection() as conn:
        row = await conn.fetchrow("""
            SELECT id, email, password_hash, first_name, last_name, role,
                   organization_id, avatar_url, is_active, last_login_at,
                   created_at, updated_at
            FROM users 
            WHERE id = $1 AND is_active = true
        """, UUID(user_id))
        
        if row:
            return {
                "id": str(row["id"]),
                "email": row["email"],
                "password_hash": row["password_hash"],
                "first_name": row["first_name"],
                "last_name": row["last_name"],
                "role": row["role"],
                "organization_id": str(row["organization_id"]) if row["organization_id"] else None,
                "avatar_url": row["avatar_url"],
                "is_active": row["is_active"],
                "last_login": row["last_login_at"],
                "created_at": row["created_at"],
                "updated_at": row["updated_at"]
            }
        return None


async def update_user_login(user_id: str) -> None:
    """Update user's last login timestamp."""
    async with get_connection() as conn:
        await conn.execute("""
            UPDATE users 
            SET last_login_at = NOW(), updated_at = NOW()
            WHERE id = $1
        """, UUID(user_id))


async def update_user_profile(
    user_id: str,
    first_name: Optional[str] = None,
    last_name: Optional[str] = None
) -> bool:
    """Update user profile information."""
    updates = []
    params = []
    param_count = 0
    
    if first_name is not None:
        param_count += 1
        updates.append(f"first_name = ${param_count}")
        params.append(first_name)
    
    if last_name is not None:
        param_count += 1
        updates.append(f"last_name = ${param_count}")
        params.append(last_name)
    
    if not updates:
        return True
    
    param_count += 1
    updates.append(f"updated_at = NOW()")
    params.append(UUID(user_id))
    
    async with get_connection() as conn:
        result = await conn.execute(f"""
            UPDATE users 
            SET {', '.join(updates)}
            WHERE id = ${param_count}
        """, *params)
        
        return result == "UPDATE 1"


async def change_password(user_id: str, new_password_hash: str) -> bool:
    """Change user password."""
    async with get_connection() as conn:
        result = await conn.execute("""
            UPDATE users 
            SET password_hash = $1, updated_at = NOW()
            WHERE id = $2
        """, new_password_hash, UUID(user_id))
        
        return result == "UPDATE 1"


# =============================================================================
# Organization Operations
# =============================================================================

async def create_organization(
    name: str,
    industry: IndustryType,
    size: CompanySize,
    country: str,
    website: Optional[str] = None,
    description: Optional[str] = None,
    owner_id: str = None,
) -> str:
    """Create a new organization and return organization ID."""
    async with get_transaction() as conn:
        # Create organization
        org_id = await conn.fetchval("""
            INSERT INTO organizations (name, industry, size, country, website, description, owner_id, plan)
            VALUES ($1, $2, $3, $4, $5, $6, $7, 'starter')
            RETURNING id
        """, name, industry.value, size.value, country, website, description, UUID(owner_id) if owner_id else None)

        await _create_subscription(conn, org_id, "starter", os.getenv("DEFAULT_BILLING_INTERVAL", "month"))
        
        # Update user's organization
        if owner_id:
            await conn.execute("""
                UPDATE users 
                SET organization_id = $1, updated_at = NOW()
                WHERE id = $2
            """, org_id, UUID(owner_id))
        
        _logger.info(f"Created organization {org_id} for user {owner_id}")
        return str(org_id)


async def get_organization_by_id(org_id: str) -> Optional[Dict[str, Any]]:
    """Get organization by ID."""
    async with get_connection() as conn:
        row = await conn.fetchrow("""
            SELECT o.id, o.name, o.industry, o.size, o.country, o.website, 
                   o.description, o.plan, o.owner_id, o.is_active,
                   o.created_at, o.updated_at,
                   COUNT(u.id) as member_count
            FROM organizations o
            LEFT JOIN users u ON u.organization_id = o.id AND u.is_active = true
            WHERE o.id = $1 AND o.is_active = true
            GROUP BY o.id, o.name, o.industry, o.size, o.country, o.website, 
                     o.description, o.plan, o.owner_id, o.is_active,
                     o.created_at, o.updated_at
        """, UUID(org_id))
        
        if row:
            return {
                "id": str(row["id"]),
                "name": row["name"],
                "industry": row["industry"],
                "size": row["size"],
                "country": row["country"],
                "website": row["website"],
                "description": row["description"],
                "plan": row["plan"],
                "owner_id": str(row["owner_id"]) if row["owner_id"] else None,
                "is_active": row["is_active"],
                "created_at": row["created_at"],
                "updated_at": row["updated_at"],
                "member_count": row["member_count"]
            }
        return None


async def get_user_organization(user_id: str) -> Optional[Dict[str, Any]]:
    """Get organization for a user."""
    user = await get_user_by_id(user_id)
    if not user or not user.get("organization_id"):
        return None
    
    return await get_organization_by_id(user["organization_id"])


async def update_organization(
    org_id: str,
    name: Optional[str] = None,
    industry: Optional[IndustryType] = None,
    size: Optional[CompanySize] = None,
    country: Optional[str] = None,
    website: Optional[str] = None,
    description: Optional[str] = None,
) -> bool:
    """Update organization information."""
    updates = []
    params = []
    param_count = 0
    
    if name is not None:
        param_count += 1
        updates.append(f"name = ${param_count}")
        params.append(name)
    
    if industry is not None:
        param_count += 1
        updates.append(f"industry = ${param_count}")
        params.append(industry.value)
    
    if size is not None:
        param_count += 1
        updates.append(f"size = ${param_count}")
        params.append(size.value)
    
    if country is not None:
        param_count += 1
        updates.append(f"country = ${param_count}")
        params.append(country)
    
    if website is not None:
        param_count += 1
        updates.append(f"website = ${param_count}")
        params.append(website)
    
    if description is not None:
        param_count += 1
        updates.append(f"description = ${param_count}")
        params.append(description)
    
    if not updates:
        return True
    
    param_count += 1
    updates.append(f"updated_at = NOW()")
    params.append(UUID(org_id))
    
    async with get_connection() as conn:
        result = await conn.execute(f"""
            UPDATE organizations 
            SET {', '.join(updates)}
            WHERE id = ${param_count}
        """, *params)
        
        return result == "UPDATE 1"


# =============================================================================
# API Key Operations  
# =============================================================================

def _generate_api_key() -> tuple[str, str, str]:
    """Generate API key, hash, and prefix."""
    key = f"sk-{secrets.token_urlsafe(32)}"
    key_hash = hashlib.sha256(key.encode()).hexdigest()
    key_prefix = key[:12]  # First 12 characters for display
    return key, key_hash, key_prefix


async def create_api_key(
    user_id: str,
    name: str,
    scopes: List[str]
) -> ApiKeyWithSecret:
    """Create a new API key for user's organization."""
    user = await get_user_by_id(user_id)
    if not user or not user.get("organization_id"):
        raise UserNotFoundError(f"User {user_id} not found or not in organization")
    
    key, key_hash, key_prefix = _generate_api_key()
    
    async with get_connection() as conn:
        api_key_id = await conn.fetchval("""
            INSERT INTO api_keys (name, key_hash, key_prefix, organization_id, created_by, scopes)
            VALUES ($1, $2, $3, $4, $5, $6)
            RETURNING id
        """, name, key_hash, key_prefix, UUID(user["organization_id"]), UUID(user_id), scopes)
    
    # Add activity log
    await add_activity(
        org_id=user["organization_id"],
        user_id=user_id,
        activity_type="api_key_created",
        title="API Key Created",
        description=f"Created API key '{name}'",
        icon="key"
    )
    
    return ApiKeyWithSecret(
        id=str(api_key_id),
        name=name,
        key=key,  # Only returned once
        key_prefix=key_prefix,
        created_at=datetime.now(timezone.utc),
        last_used_at=None,
        is_active=True,
        scopes=scopes,
        usage_count=0
    )


async def get_organization_api_keys(org_id: str) -> List[ApiKeyResponse]:
    """Get all API keys for an organization."""
    async with get_connection() as conn:
        rows = await conn.fetch("""
            SELECT id, name, key_prefix, created_at, last_used_at, 
                   is_active, scopes, usage_count
            FROM api_keys
            WHERE organization_id = $1
            ORDER BY created_at DESC
        """, UUID(org_id))
        
        return [
            ApiKeyResponse(
                id=str(row["id"]),
                name=row["name"],
                key_prefix=row["key_prefix"],
                created_at=row["created_at"],
                last_used_at=row["last_used_at"],
                is_active=row["is_active"],
                scopes=row["scopes"],
                usage_count=row["usage_count"]
            )
            for row in rows
        ]


async def revoke_api_key(key_id: str, user_id: str) -> bool:
    """Revoke an API key."""
    user = await get_user_by_id(user_id)
    if not user or not user.get("organization_id"):
        return False
    
    async with get_connection() as conn:
        result = await conn.execute("""
            UPDATE api_keys 
            SET is_active = false, revoked_at = NOW(), revoked_by = $1
            WHERE id = $2 AND organization_id = $3
        """, UUID(user_id), UUID(key_id), UUID(user["organization_id"]))
        
        if result == "UPDATE 1":
            await add_activity(
                org_id=user["organization_id"],
                user_id=user_id,
                activity_type="api_key_revoked",
                title="API Key Revoked",
                description=f"Revoked API key",
                icon="key"
            )
            return True
    
    return False


# =============================================================================
# Dashboard Statistics
# =============================================================================

async def get_dashboard_stats(org_id: str) -> DashboardStats:
    """Get dashboard statistics for an organization."""
    org = await get_organization_by_id(org_id)
    if not org:
        raise OrganizationNotFoundError(f"Organization {org_id} not found")
    
    async with get_connection() as conn:
        # Get current month usage (simulated for now)
        api_usage_current_month = 1250
        plan_limits = PLAN_CONFIGS.get(Plan(org["plan"]))
        api_usage_limit = plan_limits.requests_per_month if plan_limits else 30000
        
        # Count active API keys
        active_keys = await conn.fetchval("""
            SELECT COUNT(*) FROM api_keys 
            WHERE organization_id = $1 AND is_active = true
        """, UUID(org_id))
    
    return DashboardStats(
        api_usage_current_month=api_usage_current_month,
        api_usage_limit=api_usage_limit,
        success_rate=98.5,
        active_api_keys=active_keys or 0,
        current_plan=org["plan"],
        plan_display_name=org["plan"].title(),
        total_requests_today=85,
        total_requests_this_month=api_usage_current_month,
        avg_response_time_ms=245.0,
        error_rate=1.5,
    )


# =============================================================================
# Activity Log
# =============================================================================

async def add_activity(
    org_id: str,
    user_id: Optional[str],
    activity_type: str,
    title: str,
    description: str,
    icon: str
) -> str:
    """Add an activity log entry."""
    async with get_connection() as conn:
        activity_id = await conn.fetchval("""
            INSERT INTO activities (organization_id, user_id, activity_type, title, description, metadata)
            VALUES ($1, $2, $3, $4, $5, $6::jsonb)
            RETURNING id
        """, UUID(org_id), UUID(user_id) if user_id else None, activity_type, title, description, json.dumps({"icon": icon}))
    
    return str(activity_id)


async def get_organization_activities(org_id: str, limit: int = 20) -> List[ActivityItem]:
    """Get recent organization activities."""
    async with get_connection() as conn:
        rows = await conn.fetch("""
            SELECT a.id, a.user_id, a.activity_type, a.title, a.description, a.created_at, a.metadata,
                   u.first_name, u.last_name
            FROM activities a
            LEFT JOIN users u ON a.user_id = u.id
            WHERE a.organization_id = $1
            ORDER BY a.created_at DESC
            LIMIT $2
        """, UUID(org_id), limit)
        
        activities = []
        for row in rows:
            user_name = None
            if row["first_name"] and row["last_name"]:
                user_name = f"{row['first_name']} {row['last_name']}"

            metadata: Any = row["metadata"]
            if isinstance(metadata, str):
                try:
                    metadata = json.loads(metadata)
                except Exception:
                    metadata = {}
            if metadata is None:
                metadata = {}
            
            activities.append(ActivityItem(
                id=str(row["id"]),
                type=row["activity_type"],
                title=row["title"],
                description=row["description"],
                timestamp=row["created_at"],
                icon=metadata.get("icon", "activity"),
                user_id=str(row["user_id"]) if row["user_id"] else None,
                user_name=user_name
            ))
        
        return activities


# =============================================================================
# Usage Analytics
# =============================================================================

async def get_usage_stats(org_id: str, days: int = 30) -> List[UsageStats]:
    """Get usage statistics for an organization."""
    # Mock data for now - in production, this would query actual usage metrics
    start_date = datetime.now(timezone.utc) - timedelta(days=days)
    stats = []
    
    for i in range(days):
        date = start_date + timedelta(days=i)
        stats.append(UsageStats(
            date=date.strftime("%Y-%m-%d"),
            requests=100 + (i * 5) + (i % 7 * 3),
            errors=2 + (i % 5),
            avg_response_time_ms=200.0 + (i % 10 * 20)
        ))
    
    return stats


# =============================================================================
# Billing and Plans
# =============================================================================

async def get_available_plans() -> List[BillingPlan]:
    """Get all available billing plans."""
    return [
        BillingPlan(
            id="free",
            name="Free",
            display_name="Free Plan",
            price=0,
            currency="USD",
            interval="month",
            description="Perfect for getting started",
            features=[
                {"name": "200 API calls/month", "included": True},
                {"name": "Community support", "included": True},
                {"name": "Basic dashboard", "included": True},
                {"name": "API documentation", "included": True},
            ],
            limits={"api_calls": 200, "api_keys": 2},
        ),
        BillingPlan(
            id="free",
            name="Free",
            display_name="Free Plan (Annual)",
            price=0,
            currency="USD",
            interval="year",
            description="Perfect for getting started",
            features=[
                {"name": "200 API calls/month", "included": True},
                {"name": "Community support", "included": True},
                {"name": "Basic dashboard", "included": True},
                {"name": "API documentation", "included": True},
            ],
            limits={"api_calls": 200, "api_keys": 2},
        ),
        BillingPlan(
            id="starter",
            name="Starter",
            display_name="Starter Plan", 
            price=29,
            currency="USD",
            interval="month",
            description="For small teams and projects",
            features=[
                {"name": "1,000 API calls/month", "included": True},
                {"name": "Email support", "included": True},
                {"name": "Advanced dashboard", "included": True},
                {"name": "Basic lead scoring", "included": True},
                {"name": "2 team members", "included": True},
            ],
            limits={"api_calls": 1000, "api_keys": 5},
            is_popular=True,
        ),
        BillingPlan(
            id="starter",
            name="Starter",
            display_name="Starter Plan (Annual)",
            price=290,
            currency="USD",
            interval="year",
            description="For small teams and projects",
            features=[
                {"name": "1,000 API calls/month", "included": True},
                {"name": "Email support", "included": True},
                {"name": "Advanced dashboard", "included": True},
                {"name": "Basic lead scoring", "included": True},
                {"name": "2 team members", "included": True},
            ],
            limits={"api_calls": 1000, "api_keys": 5},
        ),
        BillingPlan(
            id="professional",
            name="Professional",
            display_name="Professional Plan",
            price=99,
            currency="USD",
            interval="month",
            description="For growing sales teams",
            features=[
                {"name": "10,000 API calls/month", "included": True},
                {"name": "Priority support", "included": True},
                {"name": "Advanced AI coaching", "included": True},
                {"name": "CRM integrations", "included": True},
                {"name": "10 team members", "included": True},
                {"name": "Custom training", "included": True},
            ],
            limits={"api_calls": 10000, "api_keys": 15},
        ),
        BillingPlan(
            id="professional",
            name="Professional",
            display_name="Professional Plan (Annual)",
            price=990,
            currency="USD",
            interval="year",
            description="For growing sales teams",
            features=[
                {"name": "10,000 API calls/month", "included": True},
                {"name": "Priority support", "included": True},
                {"name": "Advanced AI coaching", "included": True},
                {"name": "CRM integrations", "included": True},
                {"name": "10 team members", "included": True},
                {"name": "Custom training", "included": True},
            ],
            limits={"api_calls": 10000, "api_keys": 15},
        ),
        BillingPlan(
            id="enterprise",
            name="Enterprise",
            display_name="Enterprise Plan",
            price=499,
            currency="USD",
            interval="month",
            description="For large sales organizations",
            features=[
                {"name": "100,000 API calls/month", "included": True},
                {"name": "White-label solutions", "included": True},
                {"name": "Custom AI model training", "included": True},
                {"name": "Dedicated success manager", "included": True},
                {"name": "24/7 phone support", "included": True},
                {"name": "On-premise deployment", "included": True},
                {"name": "SLA guarantees", "included": True},
                {"name": "Unlimited team members", "included": True},
            ],
            limits={"api_calls": 100000, "api_keys": -1},
        ),
        BillingPlan(
            id="enterprise",
            name="Enterprise",
            display_name="Enterprise Plan (Annual)",
            price=4990,
            currency="USD",
            interval="year",
            description="For large sales organizations",
            features=[
                {"name": "100,000 API calls/month", "included": True},
                {"name": "White-label solutions", "included": True},
                {"name": "Custom AI model training", "included": True},
                {"name": "Dedicated success manager", "included": True},
                {"name": "24/7 phone support", "included": True},
                {"name": "On-premise deployment", "included": True},
                {"name": "SLA guarantees", "included": True},
                {"name": "Unlimited team members", "included": True},
            ],
            limits={"api_calls": 100000, "api_keys": -1},
        ),
    ]


# =============================================================================
# Team Management
# =============================================================================

async def get_team_members(org_id: str) -> List[TeamMember]:
    """Get all team members for an organization."""
    async with get_connection() as conn:
        rows = await conn.fetch("""
            SELECT id, email, first_name, last_name, role, is_active,
                   created_at, last_login_at
            FROM users
            WHERE organization_id = $1 AND is_active = true
            ORDER BY created_at ASC
        """, UUID(org_id))
        
        return [
            TeamMember(
                id=str(row["id"]),
                email=row["email"],
                first_name=row["first_name"],
                last_name=row["last_name"],
                role=row["role"],
                status="active" if row["is_active"] else "suspended",
                joined_at=row["created_at"],
                last_active=row["last_login_at"],
                invited_by=None  # TODO: track who invited the user
            )
            for row in rows
        ]


async def invite_team_member_to_org(
    org_id: str, 
    email: str, 
    role: UserRole, 
    invited_by: str, 
    message: Optional[str] = None
) -> bool:
    """Invite a user to join an organization."""
    # In production, this would:
    # 1. Create invitation record
    # 2. Send email invitation
    # 3. Handle invitation acceptance
    
    # For now, just log the invitation
    _logger.info(f"Team member invitation sent to {email} for org {org_id}")
    
    # Add activity log
    await add_activity(
        org_id=org_id,
        user_id=invited_by,
        activity_type="team_invite_sent",
        title="Team Member Invited",
        description=f"Invitation sent to {email} as {role}",
        icon="user-plus"
    )
    
    return True


async def update_member_role(
    org_id: str, 
    member_id: str, 
    new_role: UserRole, 
    updated_by: str
) -> bool:
    """Update a team member's role."""
    async with get_connection() as conn:
        # Get current role for logging
        current_role = await conn.fetchval("""
            SELECT role FROM users 
            WHERE id = $1 AND organization_id = $2
        """, UUID(member_id), UUID(org_id))
        
        if not current_role:
            return False
        
        result = await conn.execute("""
            UPDATE users 
            SET role = $1, updated_at = NOW()
            WHERE id = $2 AND organization_id = $3
        """, new_role.value, UUID(member_id), UUID(org_id))
        
        if result == "UPDATE 1":
            # Get user name for logging
            user = await get_user_by_id(member_id)
            user_name = f"{user['first_name']} {user['last_name']}" if user else "Unknown User"
            
            await add_activity(
                org_id=org_id,
                user_id=updated_by,
                activity_type="member_role_updated",
                title="Member Role Updated",
                description=f"Updated {user_name} from {current_role} to {new_role}",
                icon="user-check"
            )
            return True
    
    return False


async def remove_team_member_from_org(
    org_id: str, 
    member_id: str, 
    removed_by: str
) -> bool:
    """Remove a team member from organization."""
    async with get_connection() as conn:
        # Get user details for logging before removal
        user = await get_user_by_id(member_id)
        if not user or user.get("organization_id") != org_id:
            return False
        
        # Remove user from organization (don't delete the user)
        result = await conn.execute("""
            UPDATE users 
            SET organization_id = NULL, updated_at = NOW()
            WHERE id = $1 AND organization_id = $2
        """, UUID(member_id), UUID(org_id))
        
        if result == "UPDATE 1":
            user_name = f"{user['first_name']} {user['last_name']}"
            
            await add_activity(
                org_id=org_id,
                user_id=removed_by,
                activity_type="member_removed",
                title="Team Member Removed",
                description=f"Removed {user_name} from organization",
                icon="user-minus"
            )
            return True
    
    return False


# =============================================================================
# Subscription Management
# =============================================================================

async def get_subscription_details(org_id: str) -> SubscriptionResponse:
    """Get subscription details for an organization."""
    org = await get_organization_by_id(org_id)
    if not org:
        raise OrganizationNotFoundError(f"Organization {org_id} not found")
    async with get_transaction() as conn:
        row = await conn.fetchrow(
            """
            SELECT id, organization_id, plan, status, billing_interval,
                   current_period_start, current_period_end, cancel_at_period_end,
                   created_at, updated_at
            FROM subscriptions
            WHERE organization_id = $1
            """,
            UUID(org_id),
        )

        if not row:
            data = await _create_subscription(
                conn,
                UUID(org_id),
                org["plan"],
                os.getenv("DEFAULT_BILLING_INTERVAL", "month"),
            )
            row = data

    return SubscriptionResponse(
        id=str(row["id"]),
        organization_id=str(row["organization_id"]),
        plan=row["plan"],
        status=row["status"],
        billing_interval=row["billing_interval"],
        current_period_start=row["current_period_start"],
        current_period_end=row["current_period_end"],
        cancel_at_period_end=row["cancel_at_period_end"],
        created_at=row["created_at"],
        updated_at=row["updated_at"],
    )


async def upgrade_organization_plan(
    org_id: str,
    new_plan: str,
    upgraded_by: str,
    billing_interval: Optional[str] = None,
) -> bool:
    """Upgrade organization plan."""
    async with get_connection() as conn:
        # Get current plan for logging
        current_plan = await conn.fetchval("""
            SELECT plan FROM organizations WHERE id = $1
        """, UUID(org_id))
        
        if not current_plan:
            return False
        
        result = await conn.execute("""
            UPDATE organizations 
            SET plan = $1, updated_at = NOW()
            WHERE id = $2
        """, new_plan, UUID(org_id))
        
        if result == "UPDATE 1":
            if billing_interval:
                normalized_interval = _normalize_billing_interval(billing_interval)
                await conn.execute(
                    """
                    UPDATE subscriptions
                    SET plan = $1,
                        billing_interval = $2,
                        current_period_start = NOW(),
                        current_period_end = $3,
                        updated_at = NOW()
                    WHERE organization_id = $4
                    """,
                    new_plan,
                    normalized_interval,
                    _add_billing_interval(datetime.now(timezone.utc), normalized_interval),
                    UUID(org_id),
                )
            else:
                await conn.execute(
                    """
                    UPDATE subscriptions
                    SET plan = $1, updated_at = NOW()
                    WHERE organization_id = $2
                    """,
                    new_plan,
                    UUID(org_id),
                )

            await add_activity(
                org_id=org_id,
                user_id=upgraded_by,
                activity_type="plan_upgraded",
                title="Plan Upgraded",
                description=f"Upgraded from {current_plan} to {new_plan}",
                icon="arrow-up"
            )
            return True
    
    return False


# =============================================================================
# Analytics
# =============================================================================

async def get_analytics_data(org_id: str, time_range: str) -> List[AnalyticsResponse]:
    """Get analytics overview data."""
    # Mock analytics data - in production, this would query real metrics
    now = datetime.now(timezone.utc)
    days = int(time_range.rstrip('d')) if time_range.endswith('d') else 7
    
    # Generate sample data points
    data_points = []
    for i in range(days):
        timestamp = now - timedelta(days=days-i-1)
        data_points.append(TimeSeriesDataPoint(
            timestamp=timestamp,
            value=100 + (i * 10) + (i % 3 * 5),  # Mock trending data
            label=f"Day {i+1}"
        ))
    
    return [
        AnalyticsResponse(
            metric_name="API Requests",
            time_range=time_range,
            data_points=data_points,
            total=sum(dp.value for dp in data_points),
            average=sum(dp.value for dp in data_points) / len(data_points),
            change_percent=15.3
        ),
        AnalyticsResponse(
            metric_name="Success Rate",
            time_range=time_range,
            data_points=[TimeSeriesDataPoint(timestamp=dp.timestamp, value=98.5) for dp in data_points],
            total=98.5,
            average=98.5,
            change_percent=2.1
        )
    ]


async def get_detailed_usage_analytics(org_id: str, time_range: str) -> UsageAnalytics:
    """Get detailed usage analytics."""
    now = datetime.now(timezone.utc)
    days = int(time_range.rstrip('d')) if time_range.endswith('d') else 30
    
    # Generate sample time series data
    requests_data = []
    errors_data = []
    response_times = []
    
    for i in range(days):
        timestamp = now - timedelta(days=days-i-1)
        requests_data.append(TimeSeriesDataPoint(
            timestamp=timestamp,
            value=120 + (i * 5) + (i % 7 * 3),
            label=f"Requests"
        ))
        errors_data.append(TimeSeriesDataPoint(
            timestamp=timestamp,
            value=2 + (i % 5),
            label=f"Errors"
        ))
        response_times.append(TimeSeriesDataPoint(
            timestamp=timestamp,
            value=200 + (i % 10 * 20),
            label=f"Response Time (ms)"
        ))
    
    return UsageAnalytics(
        requests_over_time=requests_data,
        errors_over_time=errors_data,
        response_times=response_times,
        top_endpoints=[
            {"endpoint": "/api/v1/voice/session", "requests": 1250, "percentage": 45.2},
            {"endpoint": "/api/v1/dashboard/stats", "requests": 890, "percentage": 32.1},
            {"endpoint": "/api/v1/dashboard/usage", "requests": 630, "percentage": 22.7},
        ],
        geographic_distribution=[
            {"country": "US", "requests": 2100, "percentage": 75.8},
            {"country": "CA", "requests": 420, "percentage": 15.2},
            {"country": "UK", "requests": 250, "percentage": 9.0},
        ],
        peak_usage_hours=[9, 10, 11, 14, 15, 16]
    )


# =============================================================================
# Settings
# =============================================================================

async def get_user_settings(user_id: str) -> UserSettings:
    """Get user settings."""
    # For now, return default settings
    # In production, these would be stored in a user_settings table
    return UserSettings(
        notifications=NotificationSettings(
            email_notifications=True,
            usage_alerts=True,
            security_alerts=True,
            billing_alerts=True,
        ),
        security=SecuritySettings(
            two_factor_enabled=False,
            session_timeout_minutes=480,
        )
    )


async def update_user_settings(user_id: str, settings: UserSettings) -> bool:
    """Update user settings."""
    # In production, save to user_settings table
    _logger.info(f"Updated settings for user {user_id}")
    return True


# =============================================================================
# Password Hashing Utilities
# =============================================================================

def hash_password(password: str) -> str:
    """Hash a password using PBKDF2."""
    salt = secrets.token_hex(16)
    password_hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 100000)
    return f"{salt}:{password_hash.hex()}"


def verify_password(password: str, password_hash: str) -> bool:
    """Verify a password against its hash."""
    try:
        salt, hash_hex = password_hash.split(':')
        password_check = hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 100000)
        return hmac.compare_digest(hash_hex, password_check.hex())
    except ValueError:
        return False


# =============================================================================
# Demo Data Initialization
# =============================================================================

async def init_demo_data():
    """Initialize demo data for testing."""
    try:
        # Create demo user
        demo_user_id = await create_user(
            email="admin@salesai.com",
            password_hash=hash_password("SalesAI2026!"),
            first_name="Sales",
            last_name="Admin"
        )
        
        # Create demo organization
        demo_org_id = await create_organization(
            name="Demo Company",
            industry=IndustryType.TECHNOLOGY,
            size=CompanySize.SIZE_11_50,
            country="US",
            website="https://demo-company.com",
            description="A demo company for testing purposes",
            owner_id=demo_user_id
        )
        
        # Create demo API key
        await create_api_key(
            user_id=demo_user_id,
            name="Production API Key",
            scopes=["api:read", "api:write"]
        )
        
        # Add some demo activities
        await add_activity(
            org_id=demo_org_id,
            user_id=demo_user_id,
            activity_type="user_signup",
            title="Account Created",
            description="Demo user signed up and created organization",
            icon="user-plus"
        )
        
        _logger.info("Demo data initialized successfully")
        return demo_user_id, demo_org_id
        
    except Exception as e:
        _logger.error(f"Failed to initialize demo data: {e}")
        raise
