"""CRM Engine: customer activities, tags, loyalty, analytics.

Provides:
- Activity timeline logging and retrieval
- Customer tag management and assignment
- Loyalty points accrual, redemption, and balance tracking
- Customer analytics (LTV, frequency, churn risk)
"""

from datetime import datetime, timedelta


# ─── Customer Activities ─────────────────────────────

def log_activity(conn, customer_id, activity_type, title=None, description=None,
                 metadata=None, employee_id=None):
    """Log a customer activity to the timeline."""
    cur = conn.cursor()
    cur.execute("""
        INSERT INTO customer_activities
            (customer_id, activity_type, title, description, metadata, employee_id)
        VALUES (%s, %s, %s, %s, %s, %s)
        RETURNING id
    """, (customer_id, activity_type, title, description,
          metadata if metadata else None, employee_id))
    activity_id = cur.fetchone()[0]
    conn.commit()
    cur.close()
    return activity_id


def get_activities(conn, customer_id, activity_type=None, limit=50):
    """Get customer activity timeline."""
    cur = conn.cursor()
    params = [customer_id]
    type_filter = ""
    if activity_type:
        type_filter = "AND activity_type = %s"
        params.append(activity_type)

    cur.execute(f"""
        SELECT a.id, a.activity_type, a.title, a.description, a.metadata,
               a.employee_id, e.name as employee_name, a.created_at
        FROM customer_activities a
        LEFT JOIN employees e ON a.employee_id = e.id
        WHERE a.customer_id = %s {type_filter}
        ORDER BY a.created_at DESC
        LIMIT %s
    """, params + [limit])

    activities = []
    for r in cur.fetchall():
        activities.append({
            'id': r[0], 'activity_type': r[1], 'title': r[2],
            'description': r[3], 'metadata': r[4],
            'employee_id': r[5], 'employee_name': r[6],
            'created_at': str(r[7]),
        })
    cur.close()
    return activities


# ─── Customer Tags ─────────────────────────────

def create_tag(conn, tenant_id, name, color='#6B7280', description=None):
    cur = conn.cursor()
    cur.execute("""
        INSERT INTO customer_tags (tenant_id, name, color, description)
        VALUES (%s, %s, %s, %s)
        RETURNING id
    """, (tenant_id, name, color, description))
    tag_id = cur.fetchone()[0]
    conn.commit()
    cur.close()
    return tag_id


def list_tags(conn, tenant_id):
    cur = conn.cursor()
    cur.execute("""
        SELECT id, name, color, description, created_at
        FROM customer_tags
        WHERE tenant_id = %s
        ORDER BY name
    """, (tenant_id,))
    tags = []
    for r in cur.fetchall():
        tags.append({
            'id': r[0], 'name': r[1], 'color': r[2],
            'description': r[3], 'created_at': str(r[4]),
        })
    cur.close()
    return tags


def assign_tag(conn, customer_id, tag_id, assigned_by=None):
    cur = conn.cursor()
    cur.execute("""
        INSERT INTO customer_tag_assignments (customer_id, tag_id, assigned_by)
        VALUES (%s, %s, %s)
        ON CONFLICT (customer_id, tag_id) DO NOTHING
    """, (customer_id, tag_id, assigned_by))
    conn.commit()
    cur.close()
    return True


def remove_tag(conn, customer_id, tag_id):
    cur = conn.cursor()
    cur.execute("""
        DELETE FROM customer_tag_assignments
        WHERE customer_id = %s AND tag_id = %s
    """, (customer_id, tag_id))
    conn.commit()
    cur.close()
    return True


def get_customer_tags(conn, customer_id):
    cur = conn.cursor()
    cur.execute("""
        SELECT t.id, t.name, t.color
        FROM customer_tags t
        JOIN customer_tag_assignments a ON t.id = a.tag_id
        WHERE a.customer_id = %s
        ORDER BY t.name
    """, (customer_id,))
    tags = [{'id': r[0], 'name': r[1], 'color': r[2]} for r in cur.fetchall()]
    cur.close()
    return tags


# ─── Loyalty Program ─────────────────────────────

def add_loyalty_points(conn, customer_id, points, points_type='earned',
                       source_type=None, source_id=None, description=None,
                       expires_at=None):
    """Add loyalty points to a customer. Updates denormalized balance."""
    cur = conn.cursor()
    cur.execute("""
        INSERT INTO loyalty_points
            (customer_id, points, points_type, source_type, source_id, description, expires_at)
        VALUES (%s, %s, %s, %s, %s, %s, %s)
        RETURNING id
    """, (customer_id, points, points_type, source_type, source_id, description, expires_at))
    point_id = cur.fetchone()[0]

    # Update denormalized balance
    _recalculate_loyalty_balance(conn, customer_id, cur)

    conn.commit()
    cur.close()
    return point_id


def redeem_points(conn, customer_id, points_to_use, reward_id=None,
                  reward_value=None, description=None, employee_id=None):
    """Redeem loyalty points. Returns redemption_id or raises ValueError."""
    cur = conn.cursor()

    # Check available balance
    cur.execute("""
        SELECT COALESCE(SUM(points), 0)
        FROM loyalty_points
        WHERE customer_id = %s
          AND (expires_at IS NULL OR expires_at > NOW())
    """, (customer_id,))
    available = cur.fetchone()[0] or 0

    if available < points_to_use:
        cur.close()
        raise ValueError(f"Insufficient points: available={available}, requested={points_to_use}")

    # Record redemption
    cur.execute("""
        INSERT INTO loyalty_redemptions
            (customer_id, reward_id, points_used, reward_value, description, employee_id)
        VALUES (%s, %s, %s, %s, %s, %s)
        RETURNING id
    """, (customer_id, reward_id, points_to_use, reward_value, description, employee_id))
    redemption_id = cur.fetchone()[0]

    # Deduct points (record negative entry)
    cur.execute("""
        INSERT INTO loyalty_points
            (customer_id, points, points_type, source_type, description)
        VALUES (%s, %s, 'redeemed', 'redemption', %s)
    """, (customer_id, -points_to_use, description))

    _recalculate_loyalty_balance(conn, customer_id, cur)

    conn.commit()
    cur.close()
    return redemption_id


def _recalculate_loyalty_balance(conn, customer_id, cur=None):
    should_close = cur is None
    if should_close:
        cur = conn.cursor()

    # Calculate total non-expired points
    cur.execute("""
        SELECT COALESCE(SUM(points), 0)
        FROM loyalty_points
        WHERE customer_id = %s
          AND (expires_at IS NULL OR expires_at > NOW())
    """, (customer_id,))
    balance = cur.fetchone()[0] or 0

    # Determine tier
    tier = 'bronze'
    if balance >= 5000:
        tier = 'platinum'
    elif balance >= 2000:
        tier = 'gold'
    elif balance >= 500:
        tier = 'silver'

    cur.execute("""
        UPDATE customers
        SET loyalty_points_balance = %s, loyalty_tier = %s
        WHERE id = %s
    """, (balance, tier, customer_id))

    if should_close:
        conn.commit()
        cur.close()


def get_loyalty_history(conn, customer_id, limit=50):
    cur = conn.cursor()
    cur.execute("""
        SELECT id, points, points_type, source_type, source_id,
               description, expires_at, created_at
        FROM loyalty_points
        WHERE customer_id = %s
        ORDER BY created_at DESC
        LIMIT %s
    """, (customer_id, limit))
    history = []
    for r in cur.fetchall():
        history.append({
            'id': r[0], 'points': r[1], 'points_type': r[2],
            'source_type': r[3], 'source_id': r[4],
            'description': r[5], 'expires_at': str(r[6]) if r[6] else None,
            'created_at': str(r[7]),
        })
    cur.close()
    return history


def create_reward(conn, tenant_id, name, points_cost, reward_type='discount',
                  reward_value=None, description=None):
    cur = conn.cursor()
    cur.execute("""
        INSERT INTO loyalty_rewards
            (tenant_id, name, description, points_cost, reward_type, reward_value)
        VALUES (%s, %s, %s, %s, %s, %s)
        RETURNING id
    """, (tenant_id, name, description, points_cost, reward_type, reward_value))
    reward_id = cur.fetchone()[0]
    conn.commit()
    cur.close()
    return reward_id


def list_rewards(conn, tenant_id):
    cur = conn.cursor()
    cur.execute("""
        SELECT id, name, description, points_cost, reward_type, reward_value, is_active
        FROM loyalty_rewards
        WHERE tenant_id = %s AND is_active = true
        ORDER BY points_cost
    """, (tenant_id,))
    rewards = []
    for r in cur.fetchall():
        rewards.append({
            'id': r[0], 'name': r[1], 'description': r[2],
            'points_cost': r[3], 'reward_type': r[4], 'reward_value': float(r[5]) if r[5] else None,
            'is_active': r[6],
        })
    cur.close()
    return rewards


# ─── Customer Analytics ─────────────────────────────

def get_customer_analytics(conn, customer_id):
    """Compute LTV, purchase frequency, favorite categories, churn risk."""
    cur = conn.cursor()

    # LTV and frequency
    cur.execute("""
        SELECT
            COALESCE(SUM(total), 0) as ltv,
            COUNT(*) as total_orders,
            MIN(created_at) as first_purchase,
            MAX(created_at) as last_purchase,
            COALESCE(AVG(total), 0) as avg_order_value
        FROM sales
        WHERE customer_id = %s AND status = 'completed'
    """, (customer_id,))
    ltv, total_orders, first_purchase, last_purchase, aov = cur.fetchone()

    # Days since last purchase
    days_since_last = None
    if last_purchase:
        days_since_last = (datetime.utcnow() - last_purchase).days

    # Purchase frequency (orders per month)
    frequency = 0.0
    if first_purchase and last_purchase and total_orders > 1:
        months = max(1, (last_purchase - first_purchase).days / 30.0)
        frequency = round(total_orders / months, 2)

    # Churn risk: no purchase in 90+ days = high, 60-90 = medium, <60 = low
    churn_risk = 'low'
    if days_since_last is not None:
        if days_since_last > 90:
            churn_risk = 'high'
        elif days_since_last > 60:
            churn_risk = 'medium'

    # Favorite categories (from inventory via sale_items)
    cur.execute("""
        SELECT COALESCE(i.category_id::text, 'Uncategorized') as category,
               COUNT(*) as cnt, SUM(si.subtotal) as revenue
        FROM sale_items si
        JOIN sales s ON s.id = si.sale_id
        LEFT JOIN inventory i ON si.inventory_id = i.id
        WHERE s.customer_id = %s AND s.status = 'completed'
        GROUP BY i.category_id
        ORDER BY revenue DESC
        LIMIT 5
    """, (customer_id,))
    categories = []
    for r in cur.fetchall():
        categories.append({
            'category': r[0] or 'Uncategorized',
            'order_count': r[1],
            'revenue': float(r[2]) if r[2] else 0,
        })

    # Loyalty status
    cur.execute("""
        SELECT loyalty_points_balance, loyalty_tier
        FROM customers WHERE id = %s
    """, (customer_id,))
    row = cur.fetchone()
    loyalty_balance = row[0] or 0
    loyalty_tier = row[1] or 'bronze'

    cur.close()

    return {
        'ltv': float(ltv) if ltv else 0,
        'total_orders': total_orders or 0,
        'avg_order_value': float(aov) if aov else 0,
        'first_purchase': str(first_purchase) if first_purchase else None,
        'last_purchase': str(last_purchase) if last_purchase else None,
        'days_since_last_purchase': days_since_last,
        'purchase_frequency_monthly': frequency,
        'churn_risk': churn_risk,
        'favorite_categories': categories,
        'loyalty': {
            'points_balance': loyalty_balance,
            'tier': loyalty_tier,
        }
    }
