import json
import datetime
from pathlib import Path
from runtime.memory.vector_store import VectorStore

class DecisionMemory:
    def __init__(self, vector_store: VectorStore, data_dir: Path):
        self.vector_store = vector_store
        self.data_dir = data_dir
        self.namespace = 'decisions'

    def log_decision(self, decision: str, context: str, rationale: str, alternatives: list[str] | None = None, tags: list[str] | None = None) -> str:
        content = f"Decision: {decision}\nContext: {context}\nRationale: {rationale}"
        return self.vector_store.add(
            content=content,
            metadata={'type': 'decision', 'tags': tags or [], 'alternatives': alternatives or []},
            namespace=self.namespace
        )

    def link_outcome(self, decision_id: str, outcome: str, success: bool) -> bool:
        r = self.vector_store.get(decision_id)
        if not r:
            return False
        meta = r['metadata']
        meta['outcome'] = outcome
        meta['outcome_success'] = success
        meta['outcome_at'] = datetime.datetime.now(datetime.timezone.utc).isoformat()
        return self.vector_store.update(decision_id, metadata=meta)

    def search_decisions(self, query: str, top_k: int = 5, tags: list[str] | None = None) -> list[dict]:
        res = self.vector_store.search(query, top_k=top_k * 3, namespace=self.namespace)
        filtered = []
        for r in res:
            r_tags = r['metadata'].get('tags', [])
            if tags and not any(t in r_tags for t in tags):
                continue
            parts = r['content'].split('\n')
            decision = parts[0].replace('Decision: ', '') if len(parts) > 0 else ''
            context = parts[1].replace('Context: ', '') if len(parts) > 1 else ''
            rationale = parts[2].replace('Rationale: ', '') if len(parts) > 2 else ''
            filtered.append({
                'id': r['id'], 'decision': decision, 'context': context, 'rationale': rationale,
                'tags': r_tags, 'outcome': r['metadata'].get('outcome'), 'score': r['score']
            })
            if len(filtered) >= top_k:
                break
        return filtered

    def get_decision(self, decision_id: str) -> dict | None:
        r = self.vector_store.get(decision_id)
        if not r:
            return None
        parts = r['content'].split('\n')
        decision = parts[0].replace('Decision: ', '') if len(parts) > 0 else ''
        context = parts[1].replace('Context: ', '') if len(parts) > 1 else ''
        rationale = parts[2].replace('Rationale: ', '') if len(parts) > 2 else ''
        return {
            'decision': decision, 'context': context, 'rationale': rationale,
            'tags': r['metadata'].get('tags', []), 'alternatives': r['metadata'].get('alternatives', []),
            'outcome': r['metadata'].get('outcome'), 'outcome_success': r['metadata'].get('outcome_success')
        }

    def list_recent(self, limit: int = 20) -> list[dict]:
        res = self.vector_store.search_by_metadata({'type': 'decision'}, namespace=self.namespace, limit=limit)
        res.sort(key=lambda x: x['created_at'], reverse=True)
        out = []
        for r in res[:limit]:
            decision = r['content'].split('\n')[0].replace('Decision: ', '')
            out.append({
                'id': r['id'], 'decision': decision, 'tags': r['metadata'].get('tags', []),
                'has_outcome': 'outcome' in r['metadata'], 'created_at': r['created_at']
            })
        return out

    def list_by_tag(self, tag: str, limit: int = 20) -> list[dict]:
        res = self.vector_store.search_by_metadata({'type': 'decision'}, namespace=self.namespace, limit=1000)
        filtered = []
        for r in res:
            if tag in r['metadata'].get('tags', []):
                decision = r['content'].split('\n')[0].replace('Decision: ', '')
                filtered.append({'id': r['id'], 'decision': decision, 'tags': r['metadata'].get('tags', []), 'created_at': r['created_at']})
                if len(filtered) >= limit:
                    break
        return filtered

    def successful_patterns(self, min_decisions: int = 3) -> list[dict]:
        res = self.vector_store.search_by_metadata({'type': 'decision'}, namespace=self.namespace, limit=1000)
        tags_stats = {}
        for r in res:
            if r['metadata'].get('outcome_success'):
                for t in r['metadata'].get('tags', []):
                    if t not in tags_stats:
                        tags_stats[t] = {'count': 0, 'success': 0}
                    tags_stats[t]['count'] += 1
                    tags_stats[t]['success'] += 1
            elif 'outcome' in r['metadata']:
                for t in r['metadata'].get('tags', []):
                    if t not in tags_stats:
                        tags_stats[t] = {'count': 0, 'success': 0}
                    tags_stats[t]['count'] += 1
        patterns = []
        for t, stats in tags_stats.items():
            if stats['count'] >= min_decisions:
                patterns.append({'pattern': t, 'decision_count': stats['count'], 'success_rate': stats['success'] / stats['count']})
        return patterns

    def failed_decisions(self, limit: int = 10) -> list[dict]:
        res = self.vector_store.search_by_metadata({'type': 'decision'}, namespace=self.namespace, limit=1000)
        failed = []
        for r in res:
            if 'outcome' in r['metadata'] and not r['metadata'].get('outcome_success'):
                parts = r['content'].split('\n')
                decision = parts[0].replace('Decision: ', '') if len(parts) > 0 else ''
                context = parts[1].replace('Context: ', '') if len(parts) > 1 else ''
                failed.append({
                    'id': r['id'], 'decision': decision, 'context': context,
                    'outcome': r['metadata']['outcome'], 'created_at': r['created_at']
                })
        failed.sort(key=lambda x: x['created_at'], reverse=True)
        return failed[:limit]

    def similar_past_decisions(self, new_decision: str, top_k: int = 3) -> list[dict]:
        res = self.vector_store.search(new_decision, top_k=top_k*2, namespace=self.namespace)
        out = []
        for r in res:
            if 'outcome' in r['metadata']:
                decision = r['content'].split('\n')[0].replace('Decision: ', '')
                out.append({'decision': decision, 'outcome': r['metadata']['outcome'], 'success': r['metadata'].get('outcome_success'), 'score': r['score']})
                if len(out) >= top_k:
                    break
        return out

    def context_for_prompt(self, query: str, max_tokens: int = 600) -> str:
        res = self.search_decisions(query, top_k=5)
        max_chars = max_tokens * 4
        context = "[Relevant past decisions]\n"
        for r in res:
            outcome = f"Outcome: {r['outcome']} (Success: {r.get('outcome_success')})" if r.get('outcome') else "Outcome: pending"
            add = f"Decision: {r['decision']}\n{outcome}\n\n"
            if len(context) + len(add) > max_chars:
                break
            context += add
        context += "[End decision context]\n"
        return context

    def delete_decision(self, decision_id: str) -> bool:
        return self.vector_store.delete(decision_id)

    def get_stats(self) -> dict:
        c = self.vector_store.conn.cursor()
        c.execute("SELECT metadata, created_at FROM vectors WHERE namespace = ?", (self.namespace,))
        total = 0
        with_outcome = 0
        successes = 0
        tags_count = {}
        oldest = None
        newest = None
        for row in c.fetchall():
            total += 1
            dt = row['created_at']
            if not oldest or dt < oldest: oldest = dt
            if not newest or dt > newest: newest = dt
            meta = json.loads(row['metadata'] or '{}')
            if 'outcome' in meta:
                with_outcome += 1
                if meta.get('outcome_success'):
                    successes += 1
            for t in meta.get('tags', []):
                tags_count[t] = tags_count.get(t, 0) + 1
        top_tags = sorted(tags_count.keys(), key=lambda k: tags_count[k], reverse=True)[:5]
        return {
            'total_decisions': total, 'decisions_with_outcomes': with_outcome,
            'success_rate': successes / with_outcome if with_outcome > 0 else 0.0,
            'top_tags': top_tags, 'oldest_decision': oldest, 'newest_decision': newest
        }

    def export_decisions(self) -> list[dict]:
        res = self.vector_store.export_namespace(self.namespace)
        out = []
        for r in res:
            parts = r['content'].split('\n')
            decision = parts[0].replace('Decision: ', '') if len(parts) > 0 else ''
            context = parts[1].replace('Context: ', '') if len(parts) > 1 else ''
            rationale = parts[2].replace('Rationale: ', '') if len(parts) > 2 else ''
            out.append({
                'id': r['id'], 'decision': decision, 'context': context, 'rationale': rationale,
                'tags': r['metadata'].get('tags', []), 'alternatives': r['metadata'].get('alternatives', []),
                'outcome': r['metadata'].get('outcome'), 'created_at': r['created_at']
            })
        return out

    def import_decisions(self, data: list[dict]) -> int:
        items = []
        for d in data:
            content = f"Decision: {d['decision']}\nContext: {d['context']}\nRationale: {d['rationale']}"
            meta = {'type': 'decision', 'tags': d.get('tags', []), 'alternatives': d.get('alternatives', [])}
            if 'outcome' in d and d['outcome']:
                meta['outcome'] = d['outcome']
            items.append({'id': d['id'], 'content': content, 'metadata': meta, 'namespace': self.namespace})
        return self.vector_store.batch_add(items)
