"""
Profile Commands - Epistemic profile management

Commands:
- profile-sync: Full sync pipeline (fetch → import → optional Qdrant rebuild)
- profile-prune: Transparent artifact pruning with git notes receipts
- profile-status: Unified profile status view
- profile-import: Import epistemic artifacts from AI conversation transcripts
"""

import json
import logging
import subprocess
import time
from datetime import datetime, timezone
from typing import Any, Dict, Optional
from ..cli_utils import handle_cli_error

logger = logging.getLogger(__name__)


def _get_workspace_root() -> str:
    """Get workspace root from active context, git root, or cwd."""
    import os
    try:
        from empirica.utils.session_resolver import InstanceResolver as R
        context_project = R.project_path()
        if context_project:
            return context_project
    except Exception:
        pass
    try:
        result = subprocess.run(
            ['git', 'rev-parse', '--show-toplevel'],
            capture_output=True, text=True, timeout=5
        )
        if result.returncode == 0:
            return result.stdout.strip()
    except Exception:
        pass
    return os.getcwd()


def _load_sync_config() -> Dict[str, Any]:
    """Load sync config — reuses sync_commands logic."""
    from .sync_commands import _load_sync_config as load_config
    return load_config()


def _fetch_notes(remote: str) -> Dict[str, Any]:
    """Fetch all empirica git notes refs from remote.

    Returns dict with 'ok', 'fetched', 'errors' keys.
    """
    results = {'ok': True, 'fetched': {}, 'errors': []}

    # Fetch all empirica notes at once
    refspecs = [
        'refs/notes/empirica/*:refs/notes/empirica/*',
        'refs/notes/breadcrumbs:refs/notes/breadcrumbs',
        'refs/notes/empirica-precompact:refs/notes/empirica-precompact',
    ]

    for refspec in refspecs:
        try:
            result = subprocess.run(
                ['git', 'fetch', remote, refspec],
                capture_output=True, text=True, timeout=60,
                cwd=_get_workspace_root()
            )
            ref_name = refspec.split(':')[0].replace('refs/notes/', '')
            if result.returncode == 0:
                results['fetched'][ref_name] = True
            else:
                if 'no matching refs' not in (result.stderr or '').lower():
                    results['errors'].append(f"{ref_name}: {result.stderr.strip()}")
                results['fetched'][ref_name] = False
        except subprocess.TimeoutExpired:
            results['errors'].append(f"Fetch timed out for {refspec}")
            results['ok'] = False
        except Exception as e:
            results['errors'].append(str(e))
            results['ok'] = False

    if results['errors']:
        results['ok'] = False

    return results


def _push_notes(remote: str) -> Dict[str, Any]:
    """Push all empirica git notes refs to remote."""
    results = {'ok': True, 'pushed': {}, 'errors': []}

    refspecs = [
        'refs/notes/empirica/*:refs/notes/empirica/*',
        'refs/notes/breadcrumbs:refs/notes/breadcrumbs',
        'refs/notes/empirica-precompact:refs/notes/empirica-precompact',
    ]

    for refspec in refspecs:
        try:
            result = subprocess.run(
                ['git', 'push', remote, refspec],
                capture_output=True, text=True, timeout=60,
                cwd=_get_workspace_root()
            )
            ref_name = refspec.split(':')[0].replace('refs/notes/', '')
            if result.returncode == 0:
                results['pushed'][ref_name] = True
            else:
                if 'no matching refs' not in (result.stderr or '').lower():
                    results['errors'].append(f"{ref_name}: {result.stderr.strip()}")
                results['pushed'][ref_name] = False
        except subprocess.TimeoutExpired:
            results['errors'].append(f"Push timed out for {refspec}")
            results['ok'] = False
        except Exception as e:
            results['errors'].append(str(e))
            results['ok'] = False

    if results['errors']:
        results['ok'] = False

    return results


def _import_notes_to_sqlite() -> Dict[str, Any]:
    """Import git notes artifacts into SQLite using ProfileImporter (idempotent)."""
    try:
        from empirica.core.canonical.empirica_git.profile_import import ProfileImporter
        from empirica.data.session_database import SessionDatabase

        db = SessionDatabase()
        try:
            importer = ProfileImporter(workspace_root=_get_workspace_root())
            stats = importer.import_all(db)
            return {
                'ok': True,
                'stats': stats,
            }
        finally:
            db.close()
    except Exception as e:
        logger.warning(f"Import failed: {e}")
        return {
            'ok': False,
            'error': str(e),
        }


def _rebuild_qdrant() -> Dict[str, Any]:
    """Rebuild Qdrant semantic index from SQLite."""
    try:
        from empirica.core.qdrant.rebuild import rebuild_qdrant_from_db
        result = rebuild_qdrant_from_db()
        return {'ok': True, 'result': result}
    except ImportError:
        return {'ok': False, 'error': 'Qdrant not available (qdrant-client not installed)'}
    except Exception as e:
        return {'ok': False, 'error': str(e)}


def handle_profile_sync_command(args):
    """Handle profile-sync command — full sync pipeline."""
    try:
        sync_config = _load_sync_config()
        remote = getattr(args, 'remote', None) or sync_config.get('notes_remote', sync_config.get('remote', 'forgejo'))
        output_format = getattr(args, 'output', 'json')
        do_push = getattr(args, 'push', False)
        do_qdrant = getattr(args, 'qdrant', False)
        import_only = getattr(args, 'import_only', False)
        force = getattr(args, 'force', False)

        if not sync_config.get('enabled', True) and not force and not import_only:
            result = {
                "ok": False,
                "error": "Sync is disabled in config",
                "hint": "Run 'empirica sync-config enabled true' to enable, or use --force"
            }
            print(json.dumps(result, indent=2))
            return 1

        result = {
            "ok": True,
            "pipeline": [],
        }

        # Step 1: Fetch notes from remote (unless import-only)
        if not import_only:
            fetch_result = _fetch_notes(remote)
            result['fetch'] = fetch_result
            result['pipeline'].append('fetch')
            if not fetch_result['ok']:
                result['ok'] = False
                result['error'] = 'Fetch failed'
                print(json.dumps(result, indent=2, default=str))
                return 1

        # Step 2: Import notes to SQLite (idempotent via ProfileImporter)
        import_result = _import_notes_to_sqlite()
        result['import'] = import_result
        result['pipeline'].append('import')

        if not import_result['ok']:
            result['ok'] = False
            result['error'] = 'Import failed'

        # Step 3: Push notes to remote (if requested)
        if do_push and result['ok']:
            push_result = _push_notes(remote)
            result['push'] = push_result
            result['pipeline'].append('push')
            if not push_result['ok']:
                result['push_warning'] = 'Push had errors but import succeeded'

        # Step 4: Rebuild Qdrant (if requested)
        if do_qdrant and result['ok']:
            qdrant_result = _rebuild_qdrant()
            result['qdrant'] = qdrant_result
            result['pipeline'].append('qdrant')
            if not qdrant_result['ok']:
                result['qdrant_warning'] = 'Qdrant rebuild failed but import succeeded'

        # Summary
        summary = import_result.get('stats', {}).get('_summary', {})
        result['summary'] = {
            'imported': summary.get('imported', 0),
            'skipped': summary.get('skipped', 0),
            'total_notes': summary.get('total', 0),
        }

        if output_format == 'json':
            print(json.dumps(result, indent=2, default=str))
        else:
            if result['ok']:
                print(f"✅ Profile sync complete")
                if not import_only:
                    print(f"   Fetched from: {remote}")
                print(f"   Imported: {summary.get('imported', 0)} new artifacts")
                print(f"   Skipped: {summary.get('skipped', 0)} (already in SQLite)")
                print(f"   Total in notes: {summary.get('total', 0)}")
                # Per-type breakdown
                stats = import_result.get('stats', {})
                for artifact_type in ['findings', 'unknowns', 'dead_ends', 'mistakes', 'goals']:
                    type_stats = stats.get(artifact_type, {})
                    if type_stats.get('total', 0) > 0:
                        print(f"     {artifact_type}: {type_stats['imported']} new / {type_stats['total']} total")
                if do_push:
                    print(f"   Pushed to: {remote}")
                if do_qdrant:
                    qdrant_ok = result.get('qdrant', {}).get('ok', False)
                    print(f"   Qdrant: {'rebuilt' if qdrant_ok else 'failed'}")
            else:
                print(f"❌ Profile sync failed: {result.get('error', 'Unknown error')}")

        return 0 if result['ok'] else 1

    except Exception as e:
        handle_cli_error(e, "Profile sync", getattr(args, 'verbose', False))
        return 1


def _write_prune_receipt(artifact_id: str, artifact_type: str, reason: str,
                         artifact_summary: str) -> bool:
    """Write an immutable prune receipt to git notes.

    Receipt is stored at refs/notes/empirica/prune_receipts/<artifact_id>
    """
    receipt = {
        'artifact_id': artifact_id,
        'artifact_type': artifact_type,
        'reason': reason,
        'artifact_summary': artifact_summary,
        'pruned_at': datetime.now(timezone.utc).isoformat(),
        'pruned_by': 'empirica-profile-prune',
    }

    workspace = _get_workspace_root()
    ref = f'empirica/prune_receipts/{artifact_id}'

    try:
        # Write receipt as a git note on HEAD
        receipt_json = json.dumps(receipt, indent=2)
        result = subprocess.run(
            ['git', 'notes', f'--ref={ref}', 'add', '-f', '-m', receipt_json, 'HEAD'],
            capture_output=True, text=True, timeout=10,
            cwd=workspace
        )
        return result.returncode == 0
    except Exception as e:
        logger.warning(f"Failed to write prune receipt for {artifact_id}: {e}")
        return False


def _prune_artifact(db, artifact_id: str, artifact_type: str, reason: str) -> Dict[str, Any]:
    """Remove a single artifact from SQLite and write prune receipt."""
    table_map = {
        'finding': 'project_findings',
        'unknown': 'project_unknowns',
        'dead_end': 'project_dead_ends',
        'mistake': 'mistakes_made',
        'goal': 'goals',
    }

    table = table_map.get(artifact_type)
    if not table:
        return {'ok': False, 'error': f'Unknown artifact type: {artifact_type}'}

    # Fetch artifact summary before deletion
    cursor = db.conn.cursor()
    try:
        cursor.execute(f"SELECT * FROM {table} WHERE id = ?", (artifact_id,))
        row = cursor.fetchone()
        if not row:
            return {'ok': False, 'error': f'Artifact {artifact_id} not found in {table}'}

        # Build summary from row
        columns = [desc[0] for desc in cursor.description]
        artifact_data = dict(zip(columns, row))
        # Use a representative field for summary
        summary_field = {
            'finding': 'finding',
            'unknown': 'unknown',
            'dead_end': 'approach',
            'mistake': 'mistake',
            'goal': 'objective' if 'objective' in columns else 'id',
        }.get(artifact_type, 'id')
        artifact_summary = str(artifact_data.get(summary_field, artifact_id))[:200]

        # Write prune receipt BEFORE deletion (so we never lose the audit trail)
        receipt_written = _write_prune_receipt(artifact_id, artifact_type, reason, artifact_summary)

        # Delete from SQLite
        cursor.execute(f"DELETE FROM {table} WHERE id = ?", (artifact_id,))
        db.conn.commit()

        return {
            'ok': True,
            'artifact_id': artifact_id,
            'artifact_type': artifact_type,
            'summary': artifact_summary,
            'receipt_written': receipt_written,
        }
    except Exception as e:
        return {'ok': False, 'error': str(e)}


def _apply_prune_rule(db, rule: str, older_than_days: Optional[int] = None,
                      dry_run: bool = False) -> Dict[str, Any]:
    """Apply a mechanical pruning rule.

    Returns dict with 'ok', 'count', and 'pruned'/'candidates' keys.
    """
    cursor = db.conn.cursor()
    candidates = []
    now = time.time()
    age_cutoff = now - (older_than_days * 86400) if older_than_days else None

    if rule == 'stale-resolved-unknowns':
        query = "SELECT id, unknown, resolved_timestamp FROM project_unknowns WHERE is_resolved = 1"
        params = []
        if age_cutoff:
            query += " AND resolved_timestamp < ?"
            params.append(age_cutoff)
        cursor.execute(query, params)
        for row in cursor.fetchall():
            candidates.append({
                'id': row[0], 'type': 'unknown',
                'summary': str(row[1])[:200],
                'reason': f'Resolved unknown (stale-resolved-unknowns rule)',
            })

    elif rule == 'low-impact-findings':
        query = "SELECT id, finding, impact FROM project_findings WHERE impact < 0.3"
        params = []
        if age_cutoff:
            query += " AND created_timestamp < ?"
            params.append(age_cutoff)
        cursor.execute(query, params)
        for row in cursor.fetchall():
            candidates.append({
                'id': row[0], 'type': 'finding',
                'summary': str(row[1])[:200],
                'reason': f'Low impact ({row[2]}) finding (low-impact-findings rule)',
            })

    elif rule == 'old-dead-ends':
        threshold = age_cutoff or (now - 90 * 86400)  # default 90 days
        cursor.execute(
            "SELECT id, approach FROM project_dead_ends WHERE created_timestamp < ?",
            (threshold,)
        )
        for row in cursor.fetchall():
            candidates.append({
                'id': row[0], 'type': 'dead_end',
                'summary': str(row[1])[:200],
                'reason': 'Old dead end (old-dead-ends rule)',
            })

    elif rule == 'test-transactions':
        # Prune findings/unknowns from very short sessions (likely test runs)
        cursor.execute("""
            SELECT pf.id, pf.finding, pf.session_id
            FROM project_findings pf
            JOIN sessions s ON pf.session_id = s.session_id
            WHERE s.ai_id = 'test' OR s.ai_id LIKE 'test-%'
        """)
        for row in cursor.fetchall():
            candidates.append({
                'id': row[0], 'type': 'finding',
                'summary': str(row[1])[:200],
                'reason': f'Test session artifact (test-transactions rule)',
            })

    elif rule == 'low-confidence-imports':
        # Prune transcript-imported artifacts with low extraction confidence
        confidence_threshold = 0.6  # prune anything below this
        for table, artifact_type, text_col, data_col in [
            ('project_findings', 'finding', 'finding', 'finding_data'),
            ('project_unknowns', 'unknown', 'unknown', 'unknown_data'),
            ('project_dead_ends', 'dead_end', 'approach', 'dead_end_data'),
            ('mistakes_made', 'mistake', 'mistake', 'mistake_data'),
        ]:
            try:
                query = f"""
                    SELECT id, {text_col}, {data_col} FROM {table}
                    WHERE {data_col} LIKE '%"extraction_confidence"%'
                """
                params = []
                if age_cutoff:
                    query += " AND created_timestamp < ?"
                    params.append(age_cutoff)
                cursor.execute(query, params)
                for row in cursor.fetchall():
                    try:
                        data = json.loads(row[2]) if row[2] else {}
                        conf = data.get('extraction_confidence', 1.0)
                        if conf < confidence_threshold:
                            candidates.append({
                                'id': row[0], 'type': artifact_type,
                                'summary': str(row[1])[:200],
                                'reason': f'Low confidence transcript import ({conf:.2f} < {confidence_threshold}) (low-confidence-imports rule)',
                            })
                    except (json.JSONDecodeError, TypeError):
                        pass
            except Exception:
                pass

    elif rule == 'falsified-assumptions':
        # This would need an assumptions table — skip for now if not available
        return {'ok': True, 'candidates': [], 'note': 'Assumptions table not yet supported for pruning'}

    if dry_run:
        return {
            'ok': True,
            'dry_run': True,
            'candidates': candidates,
            'count': len(candidates),
        }

    # Actually prune
    pruned = []
    errors = []
    for candidate in candidates:
        result = _prune_artifact(
            db, candidate['id'], candidate['type'], candidate['reason']
        )
        if result['ok']:
            pruned.append(result)
        else:
            errors.append(result)

    return {
        'ok': len(errors) == 0,
        'pruned': pruned,
        'errors': errors,
        'count': len(pruned),
    }


def handle_profile_prune_command(args):
    """Handle profile-prune command — transparent artifact pruning."""
    try:
        rule = getattr(args, 'rule', None)
        artifact_id = getattr(args, 'artifact_id', None)
        artifact_type = getattr(args, 'artifact_type', None)
        reason = getattr(args, 'reason', None)
        older_than = getattr(args, 'older_than', None)
        dry_run = getattr(args, 'dry_run', False)
        output_format = getattr(args, 'output', 'json')

        if not rule and not artifact_id:
            result = {
                "ok": False,
                "error": "Specify --rule for rule-based pruning or --artifact-id for specific artifact pruning",
                "available_rules": [
                    'stale-resolved-unknowns',
                    'test-transactions',
                    'low-impact-findings',
                    'old-dead-ends',
                ],
            }
            print(json.dumps(result, indent=2))
            return 1

        from empirica.data.session_database import SessionDatabase
        db = SessionDatabase()

        try:
            if artifact_id:
                if not artifact_type:
                    result = {"ok": False, "error": "--artifact-type required with --artifact-id"}
                    print(json.dumps(result, indent=2))
                    return 1

                if dry_run:
                    result = {
                        "ok": True,
                        "dry_run": True,
                        "would_prune": {
                            "artifact_id": artifact_id,
                            "artifact_type": artifact_type,
                            "reason": reason or "Manual prune",
                        }
                    }
                else:
                    result = _prune_artifact(db, artifact_id, artifact_type, reason or "Manual prune")
            else:
                assert rule is not None  # guaranteed by earlier check
                result = _apply_prune_rule(db, rule, older_than, dry_run)
        finally:
            db.close()

        if output_format == 'json':
            print(json.dumps(result, indent=2, default=str))
        else:
            if dry_run:
                count = result.get('count', 0)
                candidates = result.get('candidates', [])
                print(f"🔍 Dry run: {count} artifacts would be pruned")
                for c in candidates[:20]:
                    print(f"   [{c['type']}] {c['id'][:12]}... — {c['summary'][:60]}")
                if count > 20:
                    print(f"   ... and {count - 20} more")
            elif result.get('ok'):
                count = result.get('count', 1)
                print(f"✅ Pruned {count} artifact(s) with receipts in git notes")
            else:
                print(f"❌ Prune failed: {result.get('error', 'Unknown error')}")

        return 0 if result.get('ok') else 1

    except Exception as e:
        handle_cli_error(e, "Profile prune", getattr(args, 'verbose', False))
        return 1


def handle_profile_status_command(args):
    """Handle profile-status command — unified profile view."""
    try:
        output_format = getattr(args, 'output', 'json')
        sync_config = _load_sync_config()
        remote = getattr(args, 'remote', None) or sync_config.get('notes_remote', sync_config.get('remote', 'forgejo'))

        from empirica.data.session_database import SessionDatabase
        db = SessionDatabase()
        try:
            cursor = db.conn.cursor()

            # Artifact counts from SQLite
            artifact_counts = {}
            tables = {
                'findings': 'project_findings',
                'unknowns': 'project_unknowns',
                'dead_ends': 'project_dead_ends',
                'mistakes': 'mistakes_made',
                'goals': 'goals',
            }
            for name, table in tables.items():
                try:
                    cursor.execute(f"SELECT COUNT(*) FROM {table}")
                    artifact_counts[name] = cursor.fetchone()[0]
                except Exception:
                    artifact_counts[name] = -1  # table doesn't exist

            # Resolved unknowns count
            try:
                cursor.execute("SELECT COUNT(*) FROM project_unknowns WHERE is_resolved = 1")
                artifact_counts['unknowns_resolved'] = cursor.fetchone()[0]
            except Exception:
                artifact_counts['unknowns_resolved'] = 0

            # Session count
            try:
                cursor.execute("SELECT COUNT(*) FROM sessions")
                artifact_counts['sessions'] = cursor.fetchone()[0]
            except Exception:
                artifact_counts['sessions'] = 0

            # Transaction count
            try:
                cursor.execute("SELECT COUNT(*) FROM epistemic_snapshots WHERE snapshot_type IN ('preflight', 'postflight')")
                artifact_counts['snapshots'] = cursor.fetchone()[0]
            except Exception:
                artifact_counts['snapshots'] = 0
        finally:
            db.close()

        # Git notes counts (canonical)
        notes_counts = {}
        workspace = _get_workspace_root()
        for ref_name in ['empirica/findings', 'empirica/unknowns', 'empirica/dead_ends',
                         'empirica/mistakes', 'empirica/goals', 'empirica/sessions']:
            try:
                result = subprocess.run(
                    ['git', 'for-each-ref', f'refs/notes/{ref_name}/'],
                    capture_output=True, text=True, timeout=10,
                    cwd=workspace
                )
                if result.returncode == 0:
                    count = len([l for l in result.stdout.strip().split('\n') if l.strip()])
                    notes_counts[ref_name.split('/')[-1]] = count
            except Exception:
                pass

        # Sync state
        sync_available = False
        try:
            result = subprocess.run(
                ['git', 'remote', 'get-url', remote],
                capture_output=True, text=True, timeout=5,
                cwd=workspace
            )
            sync_available = result.returncode == 0
        except Exception:
            pass

        # Calibration summary
        calibration = {}
        try:
            from pathlib import Path
            import yaml
            breadcrumbs_path = Path(workspace) / '.breadcrumbs.yaml'
            if breadcrumbs_path.exists():
                with open(breadcrumbs_path) as f:
                    bc = yaml.safe_load(f) or {}
                cal = bc.get('calibration', {})
                if cal:
                    calibration['observations'] = cal.get('observations', 0)
                gcal = bc.get('grounded_calibration', {})
                if gcal:
                    calibration['grounded_observations'] = gcal.get('total_observations', 0)
                    calibration['grounded_score'] = gcal.get('latest_score')
                    calibration['grounded_coverage'] = gcal.get('latest_coverage')
        except Exception:
            pass

        # Transcript import stats
        import_stats = {'total': 0, 'by_source': {}, 'by_type': {}}
        try:
            from empirica.data.session_database import SessionDatabase as _DB2
            db2 = _DB2()
            try:
                c2 = db2.conn.cursor()
                for table, artifact_type, data_col in [
                    ('project_findings', 'findings', 'finding_data'),
                    ('project_unknowns', 'unknowns', 'unknown_data'),
                    ('project_dead_ends', 'dead_ends', 'dead_end_data'),
                    ('mistakes_made', 'mistakes', 'mistake_data'),
                ]:
                    try:
                        c2.execute(f"""
                            SELECT {data_col} FROM {table}
                            WHERE {data_col} LIKE '%"extraction_confidence"%'
                        """)
                        for row in c2.fetchall():
                            try:
                                data = json.loads(row[0]) if row[0] else {}
                                source = data.get('source', 'unknown')
                                import_stats['total'] += 1
                                import_stats['by_source'][source] = import_stats['by_source'].get(source, 0) + 1
                                import_stats['by_type'][artifact_type] = import_stats['by_type'].get(artifact_type, 0) + 1
                            except (json.JSONDecodeError, TypeError):
                                pass
                    except Exception:
                        pass
            finally:
                db2.close()
        except Exception:
            pass

        # Drift detection: notes vs SQLite
        drift = {}
        for artifact_type in ['findings', 'unknowns', 'dead_ends', 'mistakes', 'goals']:
            notes_count = notes_counts.get(artifact_type, 0)
            sqlite_count = artifact_counts.get(artifact_type, 0)
            if notes_count > 0 and sqlite_count >= 0:
                diff = notes_count - sqlite_count
                if diff != 0:
                    drift[artifact_type] = {
                        'notes': notes_count,
                        'sqlite': sqlite_count,
                        'delta': diff,
                    }

        result = {
            "ok": True,
            "artifacts": {
                "sqlite": artifact_counts,
                "git_notes": notes_counts,
            },
            "transcript_imports": import_stats if import_stats['total'] > 0 else None,
            "drift": drift if drift else None,
            "sync": {
                "remote": remote,
                "available": sync_available,
                "enabled": sync_config.get('enabled', True),
            },
            "calibration": calibration if calibration else None,
        }

        if output_format == 'json':
            print(json.dumps(result, indent=2, default=str))
        else:
            print("📊 Epistemic Profile Status")
            print("=" * 50)

            # Artifact counts
            total_sqlite = sum(v for v in artifact_counts.values() if isinstance(v, int) and v > 0)
            total_notes = sum(notes_counts.values())
            print(f"\n  Artifacts (SQLite): {total_sqlite}")
            for name, count in artifact_counts.items():
                if count > 0 and name not in ('unknowns_resolved', 'sessions', 'snapshots'):
                    print(f"    {name}: {count}")
            if artifact_counts.get('unknowns_resolved', 0) > 0:
                print(f"    unknowns (resolved): {artifact_counts['unknowns_resolved']}")
            print(f"    sessions: {artifact_counts.get('sessions', 0)}")
            print(f"    snapshots: {artifact_counts.get('snapshots', 0)}")

            print(f"\n  Artifacts (Git Notes): {total_notes}")
            for name, count in notes_counts.items():
                if count > 0:
                    print(f"    {name}: {count}")

            # Transcript imports
            if import_stats['total'] > 0:
                print(f"\n  Transcript Imports: {import_stats['total']}")
                for src, count in import_stats['by_source'].items():
                    print(f"    source={src}: {count}")
                for atype, count in import_stats['by_type'].items():
                    print(f"    {atype}: {count}")

            # Drift
            if drift:
                print(f"\n  ⚠️  Drift detected (notes - sqlite):")
                for artifact_type, info in drift.items():
                    print(f"    {artifact_type}: {info['delta']:+d} (notes={info['notes']}, sqlite={info['sqlite']})")
                print(f"    Run 'empirica profile-sync --import-only' to reconcile")

            # Sync
            print(f"\n  Sync: {'enabled' if sync_config.get('enabled') else 'disabled'}, "
                  f"remote={remote} ({'configured' if sync_available else 'NOT configured'})")

            # Calibration
            if calibration:
                print(f"\n  Calibration:")
                if 'observations' in calibration:
                    print(f"    Self-referential observations: {calibration['observations']}")
                if 'grounded_score' in calibration:
                    print(f"    Grounded score: {calibration.get('grounded_score', 'N/A')}")
                    print(f"    Grounded coverage: {calibration.get('grounded_coverage', 'N/A')}")

        return 0

    except Exception as e:
        handle_cli_error(e, "Profile status", getattr(args, 'verbose', False))
        return 1


def handle_profile_import_command(args):
    """Handle profile-import command — mine AI transcripts for epistemic artifacts."""
    try:
        source = getattr(args, 'source', 'claude-code')
        project_name = getattr(args, 'project', None)
        file_path = getattr(args, 'file', None)
        session_id_filter = getattr(args, 'session', None)
        min_confidence = getattr(args, 'min_confidence', 0.5)
        dry_run = getattr(args, 'dry_run', False)
        include_sidechains = getattr(args, 'include_sidechains', False)
        output_format = getattr(args, 'output', 'text')

        from empirica.core.canonical.transcript_parser import (
            TranscriptParser, SessionIndex, ClaudeAIParser
        )
        from empirica.core.canonical.artifact_extractor import ArtifactExtractor

        all_results = []
        sessions_scanned = 0

        if source == 'claude-code':
            session_index = SessionIndex()
            parser = TranscriptParser()

            # Discover sessions to process
            if project_name:
                sessions = session_index.get_sessions(project_name)
            else:
                sessions = session_index.get_all_sessions(min_messages=3)

            if session_id_filter:
                sessions = [s for s in sessions if s.session_id == session_id_filter]

            if not sessions:
                msg = "No sessions found"
                if project_name:
                    msg += f" in project '{project_name}'"
                if output_format == 'json':
                    print(json.dumps({"ok": True, "message": msg, "sessions_scanned": 0, "artifacts": 0}))
                else:
                    print(f"ℹ️  {msg}")
                return 0

            if output_format == 'text' and not dry_run:
                print(f"🔍 Scanning {len(sessions)} session(s)...")

            for session_meta in sessions:
                if not session_meta.full_path:
                    continue
                sessions_scanned += 1

                records = parser.parse_session(session_meta.full_path)
                if not records:
                    continue

                turns = list(parser.iter_conversation_turns(
                    records, include_sidechains=include_sidechains
                ))
                if not turns:
                    continue

                extractor = ArtifactExtractor(min_confidence=min_confidence)
                result = extractor.extract_all(
                    turns,
                    source="claude-code",
                    session_id=session_meta.session_id,
                )

                if result.total_artifacts > 0:
                    all_results.append(result)

                    if output_format == 'text' and not dry_run:
                        summary = result.summary()
                        parts = []
                        for key in ['findings', 'decisions', 'dead_ends', 'mistakes', 'unknowns']:
                            if summary[key] > 0:
                                parts.append(f"{key}={summary[key]}")
                        if parts:
                            session_label = session_meta.summary or session_meta.session_id[:12]
                            print(f"   {session_label}: {', '.join(parts)}")

        elif source == 'claude-ai':
            if not file_path:
                error = {"ok": False, "error": "--file required for --source claude-ai"}
                if output_format == 'json':
                    print(json.dumps(error))
                else:
                    print(f"❌ {error['error']}")
                return 1

            ai_parser = ClaudeAIParser()
            turns, metadata = ai_parser.parse_export(file_path)

            if not turns:
                msg = f"No conversations found in {file_path}"
                if output_format == 'json':
                    print(json.dumps({"ok": True, "message": msg, "sessions_scanned": 0, "artifacts": 0}))
                else:
                    print(f"ℹ️  {msg}")
                return 0

            sessions_scanned = metadata.get('conversation_count', 1)

            if output_format == 'text' and not dry_run:
                print(f"🔍 Processing {len(turns)} conversation turns from Claude.ai export...")

            extractor = ArtifactExtractor(min_confidence=min_confidence)
            result = extractor.extract_all(turns, source="claude-ai")

            if result.total_artifacts > 0:
                all_results.append(result)

        # Aggregate results
        totals = {
            'findings': sum(len(r.findings) for r in all_results),
            'decisions': sum(len(r.decisions) for r in all_results),
            'dead_ends': sum(len(r.dead_ends) for r in all_results),
            'mistakes': sum(len(r.mistakes) for r in all_results),
            'unknowns': sum(len(r.unknowns) for r in all_results),
        }
        total_artifacts = sum(totals.values())

        if dry_run:
            # Show what would be imported
            report = {
                "ok": True,
                "dry_run": True,
                "source": source,
                "sessions_scanned": sessions_scanned,
                "artifacts_found": totals,
                "total": total_artifacts,
                "min_confidence": min_confidence,
            }

            # Include sample artifacts in dry run
            samples = {}
            for r in all_results:
                if r.findings and 'finding' not in samples:
                    f = r.findings[0]
                    samples['finding'] = {'text': f.finding, 'confidence': f.confidence, 'impact': f.impact}
                if r.decisions and 'decision' not in samples:
                    d = r.decisions[0]
                    samples['decision'] = {'choice': d.choice, 'confidence': d.confidence}
                if r.dead_ends and 'dead_end' not in samples:
                    de = r.dead_ends[0]
                    samples['dead_end'] = {'approach': de.approach, 'confidence': de.confidence}
            if samples:
                report['samples'] = samples

            if output_format == 'json':
                print(json.dumps(report, indent=2))
            else:
                print(f"\n📋 Dry run: {total_artifacts} artifacts found from {sessions_scanned} session(s)")
                for artifact_type, count in totals.items():
                    if count > 0:
                        print(f"   {artifact_type}: {count}")
                if samples:
                    print(f"\n   Sample artifacts:")
                    for atype, sample in samples.items():
                        text = sample.get('text', sample.get('choice', sample.get('approach', '')))
                        print(f"   [{atype}] {text[:80]}... (confidence={sample['confidence']})")
            return 0

        # Actually store artifacts
        if total_artifacts == 0:
            msg = f"No artifacts found above confidence {min_confidence}"
            if output_format == 'json':
                print(json.dumps({"ok": True, "message": msg, "sessions_scanned": sessions_scanned, "artifacts": 0}))
            else:
                print(f"ℹ️  {msg}")
            return 0

        from empirica.data.session_database import SessionDatabase
        from empirica.utils.session_resolver import get_active_project_id
        import uuid as uuid_mod

        db = SessionDatabase()
        project_id = get_active_project_id()
        stored = {'findings': 0, 'unknowns': 0, 'dead_ends': 0, 'mistakes': 0}

        try:
            cursor = db.conn.cursor()
            now_ts = datetime.now(timezone.utc).timestamp()

            for result in all_results:
                for finding in result.findings:
                    try:
                        cursor.execute("""
                            INSERT OR IGNORE INTO project_findings
                            (id, project_id, session_id, finding, created_timestamp,
                             finding_data, impact)
                            VALUES (?, ?, ?, ?, ?, ?, ?)
                        """, (
                            str(uuid_mod.uuid4()),
                            project_id,
                            result.session_id,
                            finding.finding,
                            now_ts,
                            json.dumps({
                                'finding': finding.finding,
                                'source': result.source,
                                'extraction_confidence': finding.confidence,
                                'source_turn': finding.source_turn,
                            }),
                            finding.impact,
                        ))
                        if cursor.rowcount > 0:
                            stored['findings'] += 1
                    except Exception as e:
                        logger.debug(f"Failed to store finding: {e}")

                for unknown in result.unknowns:
                    try:
                        cursor.execute("""
                            INSERT OR IGNORE INTO project_unknowns
                            (id, project_id, session_id, unknown, is_resolved,
                             created_timestamp, unknown_data, impact)
                            VALUES (?, ?, ?, ?, ?, ?, ?, ?)
                        """, (
                            str(uuid_mod.uuid4()),
                            project_id,
                            result.session_id,
                            unknown.unknown,
                            False,
                            now_ts,
                            json.dumps({
                                'unknown': unknown.unknown,
                                'source': result.source,
                                'extraction_confidence': unknown.confidence,
                            }),
                            0.5,
                        ))
                        if cursor.rowcount > 0:
                            stored['unknowns'] += 1
                    except Exception as e:
                        logger.debug(f"Failed to store unknown: {e}")

                for dead_end in result.dead_ends:
                    try:
                        cursor.execute("""
                            INSERT OR IGNORE INTO project_dead_ends
                            (id, project_id, session_id, approach, why_failed,
                             created_timestamp, dead_end_data)
                            VALUES (?, ?, ?, ?, ?, ?, ?)
                        """, (
                            str(uuid_mod.uuid4()),
                            project_id,
                            result.session_id,
                            dead_end.approach,
                            dead_end.why_failed,
                            now_ts,
                            json.dumps({
                                'source': result.source,
                                'extraction_confidence': dead_end.confidence,
                            }),
                        ))
                        if cursor.rowcount > 0:
                            stored['dead_ends'] += 1
                    except Exception as e:
                        logger.debug(f"Failed to store dead end: {e}")

                for mistake in result.mistakes:
                    try:
                        cursor.execute("""
                            INSERT OR IGNORE INTO mistakes_made
                            (id, project_id, session_id, mistake, why_wrong,
                             prevention, created_timestamp, mistake_data)
                            VALUES (?, ?, ?, ?, ?, ?, ?, ?)
                        """, (
                            str(uuid_mod.uuid4()),
                            project_id,
                            result.session_id,
                            mistake.mistake,
                            mistake.why_wrong,
                            mistake.prevention,
                            now_ts,
                            json.dumps({
                                'source': result.source,
                                'extraction_confidence': mistake.confidence,
                            }),
                        ))
                        if cursor.rowcount > 0:
                            stored['mistakes'] += 1
                    except Exception as e:
                        logger.debug(f"Failed to store mistake: {e}")

            db.conn.commit()
        finally:
            db.close()

        total_stored = sum(stored.values())
        report = {
            "ok": True,
            "source": source,
            "sessions_scanned": sessions_scanned,
            "artifacts_found": total_artifacts,
            "artifacts_stored": stored,
            "total_stored": total_stored,
            "duplicates_skipped": total_artifacts - total_stored,
        }

        if output_format == 'json':
            print(json.dumps(report, indent=2))
        else:
            print(f"\n✅ Imported {total_stored} artifacts from {sessions_scanned} session(s)")
            for artifact_type, count in stored.items():
                if count > 0:
                    print(f"   {artifact_type}: {count}")
            skipped = total_artifacts - total_stored
            if skipped > 0:
                print(f"   ({skipped} duplicates skipped)")

        return 0

    except Exception as e:
        handle_cli_error(e, "Profile import", getattr(args, 'verbose', False))
        return 1
