"""
Pattern Detection
Analyzes usage data to detect workflows, peak hours, and preferences.
"""
from typing import Dict, Any, List
import sqlite3
import time
from collections import Counter
from .usage_tracker import UsageTracker

class PatternDetector:
    def __init__(self, tracker: UsageTracker):
        self.tracker = tracker

    def frequent_chains(self, min_count: int = 3) -> List[Dict[str, Any]]:
        with sqlite3.connect(self.tracker.db_path) as conn:
            c = conn.cursor()
            cutoff = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(time.time() - 30 * 86400))
            c.execute('''SELECT strategy, model, COUNT(*), AVG(latency_ms)
                         FROM interactions WHERE timestamp >= ?
                         GROUP BY strategy, model HAVING COUNT(*) >= ?
                         ORDER BY COUNT(*) DESC''', (cutoff, min_count))
            return [{"strategy": r[0], "models": [r[1]], "count": r[2], "avg_latency_ms": r[3]} for r in c.fetchall()]

    def time_patterns(self) -> Dict[str, Any]:
        dist = self.tracker.hourly_distribution()
        if not dist:
            return {"peak_hour": None, "peak_count": 0, "quiet_hours": [], "weekend_vs_weekday_ratio": 0.0}
        
        peak_hour = max(dist.items(), key=lambda x: x[1])[0]
        peak_count = dist[peak_hour]
        quiet_hours = [h for h, c in dist.items() if c == 0]
        
        # Approximate weekend vs weekday ratio
        with sqlite3.connect(self.tracker.db_path) as conn:
            c = conn.cursor()
            cutoff = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(time.time() - 30 * 86400))
            c.execute('''SELECT CAST(strftime('%w', timestamp) AS INTEGER), COUNT(*)
                         FROM interactions WHERE timestamp >= ?
                         GROUP BY strftime('%w', timestamp)''', (cutoff,))
            days = dict(c.fetchall())
            weekend = days.get(0, 0) + days.get(6, 0) # 0=Sun, 6=Sat
            weekday = sum(days.get(i, 0) for i in range(1, 6))
            ratio = (weekend / 2.0) / (weekday / 5.0) if weekday > 0 else 0.0
            
        return {
            "peak_hour": peak_hour,
            "peak_count": peak_count,
            "quiet_hours": quiet_hours,
            "weekend_vs_weekday_ratio": ratio
        }

    def task_type_clusters(self, min_cluster: int = 5) -> List[Dict[str, Any]]:
        # Mocking task_type since we don't store prompt text in DB for privacy
        with sqlite3.connect(self.tracker.db_path) as conn:
            c = conn.cursor()
            c.execute('''SELECT strategy, model, COUNT(*)
                         FROM interactions GROUP BY strategy, model HAVING COUNT(*) >= ?
                         ORDER BY COUNT(*) DESC''', (min_cluster,))
            return [{"task_type": r[0], "count": r[2], "preferred_model": r[1], "preferred_strategy": r[0]} for r in c.fetchall()]

    def model_preferences(self) -> Dict[str, Any]:
        top = self.tracker.top_models(limit=10)
        if not top:
            return {"primary_model": None, "fallback_model": None, "avoid_models": []}
            
        primary = top[0]["model"]
        fallback = top[1]["model"] if len(top) > 1 else None
        avoid = [m["model"] for m in top if m["success_rate"] < 0.8]
        return {"primary_model": primary, "fallback_model": fallback, "avoid_models": avoid}

    def strategy_preferences(self) -> Dict[str, Any]:
        with sqlite3.connect(self.tracker.db_path) as conn:
            c = conn.cursor()
            c.execute('''SELECT strategy, COUNT(*), SUM(CASE WHEN status='success' THEN 1 ELSE 0 END)*1.0/COUNT(*), AVG(latency_ms)
                         FROM interactions GROUP BY strategy ORDER BY COUNT(*) DESC''')
            rows = c.fetchall()
            if not rows:
                return {"preferred_strategy": None, "success_rates": {}, "latency_comparison": {}}
                
            return {
                "preferred_strategy": rows[0][0],
                "success_rates": {r[0]: r[2] for r in rows},
                "latency_comparison": {r[0]: r[3] for r in rows}
            }

    def workflow_sequences(self, min_length: int = 2) -> List[List[str]]:
        with sqlite3.connect(self.tracker.db_path) as conn:
            c = conn.cursor()
            c.execute('SELECT session_id, strategy FROM interactions ORDER BY session_id, timestamp')
            sessions = {}
            for sid, strat in c.fetchall():
                if sid not in sessions:
                    sessions[sid] = []
                sessions[sid].append(strat)
                
            sequences = Counter()
            for seq in sessions.values():
                if len(seq) >= min_length:
                    sequences[tuple(seq)] += 1
            
            return [list(seq) for seq, _ in sequences.most_common(5)]

    def detect_degradation(self, model: str, window_days: int = 7) -> Dict[str, Any]:
        with sqlite3.connect(self.tracker.db_path) as conn:
            c = conn.cursor()
            now = time.time()
            recent_cutoff = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(now - window_days * 86400))
            old_cutoff = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(now - 2 * window_days * 86400))
            
            c.execute('''SELECT AVG(latency_ms), SUM(CASE WHEN status!='success' THEN 1 ELSE 0 END)*1.0/COUNT(*)
                         FROM interactions WHERE model=? AND timestamp >= ?''', (model, recent_cutoff))
            recent = c.fetchone()
            
            c.execute('''SELECT AVG(latency_ms), SUM(CASE WHEN status!='success' THEN 1 ELSE 0 END)*1.0/COUNT(*)
                         FROM interactions WHERE model=? AND timestamp >= ? AND timestamp < ?''', (model, old_cutoff, recent_cutoff))
            old = c.fetchone()
            
            if not recent[0] or not old[0]:
                return None
                
            lat_change = ((recent[0] - old[0]) / old[0]) * 100
            err_change = ((recent[1] - old[1]) / old[1]) * 100 if old[1] > 0 else (100 if recent[1] > 0 else 0)
            
            if lat_change > 20 or err_change > 20:
                return {"model": model, "latency_change_pct": lat_change, "error_rate_change_pct": err_change}
            return None

    def peak_usage_windows(self, days: int = 14) -> List[Dict[str, Any]]:
        dist = self.tracker.hourly_distribution(days)
        windows = []
        for i in range(0, 24, 2):
            windows.append({
                "start_hour": i,
                "end_hour": i+2,
                "avg_interactions": (dist.get(i, 0) + dist.get(i+1, 0)) / float(days)
            })
        return sorted(windows, key=lambda x: x["avg_interactions"], reverse=True)[:3]

    def session_length_trend(self, days: int = 30) -> Dict[str, Any]:
        sessions = self.tracker.get_sessions(days=days, limit=100)
        if not sessions:
            return {"avg_session_length_min": 0, "trend": "stable", "sessions_analyzed": 0}
            
        avg = sum(s["duration_minutes"] for s in sessions) / len(sessions)
        return {"avg_session_length_min": avg, "trend": "stable", "sessions_analyzed": len(sessions)}

    def model_switching_rate(self, days: int = 30) -> float:
        with sqlite3.connect(self.tracker.db_path) as conn:
            c = conn.cursor()
            cutoff = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(time.time() - days * 86400))
            c.execute('SELECT session_id, model FROM interactions WHERE timestamp >= ? ORDER BY session_id, timestamp', (cutoff,))
            
            switches = 0
            total_transitions = 0
            
            last_sid = None
            last_model = None
            for sid, model in c.fetchall():
                if sid == last_sid:
                    total_transitions += 1
                    if model != last_model:
                        switches += 1
                last_sid = sid
                last_model = model
                
            return switches / float(total_transitions) if total_transitions > 0 else 0.0

    def unused_models(self, days: int = 30) -> List[str]:
        # Assume these are all available
        available = ["claude", "gemini", "ollama:llama3"] 
        top = self.tracker.top_models(days)
        used = [m["model"] for m in top]
        return [m for m in available if m not in used]

    def generate_report(self) -> Dict[str, Any]:
        return {
            "frequency": self.frequent_chains(),
            "timing": self.time_patterns(),
            "models": self.model_preferences(),
            "strategies": self.strategy_preferences(),
            "workflows": self.workflow_sequences()
        }
