#!/usr/bin/env python3
"""
Migrate Graphiti data between databases and group_ids.

Usage:
    python migrate_group_id.py

This script migrates data from:
    Source: neo4j database, group_id='lvarming73'
    Target: graphiti database, group_id='6910959f2128b5c4faa22283'
"""

import os

from neo4j import GraphDatabase

# Configuration
NEO4J_URI = 'bolt://192.168.1.25:7687'
NEO4J_USER = 'neo4j'
NEO4J_PASSWORD = os.environ.get('NEO4J_PASSWORD', '!"MiTa1205')

SOURCE_DATABASE = 'neo4j'
SOURCE_GROUP_ID = 'lvarming73'

TARGET_DATABASE = 'graphiti'
TARGET_GROUP_ID = '6910959f2128b5c4faa22283'


def migrate_data():
    """Migrate all nodes and relationships from source to target."""

    driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD))

    try:
        # Step 1: Export data from source database
        print(
            f'\n📤 Exporting data from {SOURCE_DATABASE} database (group_id: {SOURCE_GROUP_ID})...'
        )

        with driver.session(database=SOURCE_DATABASE) as session:
            # Get all nodes with the source group_id
            nodes_result = session.run(
                """
                MATCH (n {group_id: $group_id})
                RETURN
                    id(n) as old_id,
                    labels(n) as labels,
                    properties(n) as props
                ORDER BY old_id
            """,
                group_id=SOURCE_GROUP_ID,
            )

            nodes = list(nodes_result)
            print(f'   Found {len(nodes)} nodes to migrate')

            if len(nodes) == 0:
                print('   ⚠️  No nodes found. Nothing to migrate.')
                return

            # Get all relationships between nodes with the source group_id
            rels_result = session.run(
                """
                MATCH (n {group_id: $group_id})-[r]->(m {group_id: $group_id})
                RETURN
                    id(startNode(r)) as from_id,
                    id(endNode(r)) as to_id,
                    type(r) as rel_type,
                    properties(r) as props
            """,
                group_id=SOURCE_GROUP_ID,
            )

            relationships = list(rels_result)
            print(f'   Found {len(relationships)} relationships to migrate')

        # Step 2: Create ID mapping (old Neo4j internal ID -> new node UUID)
        print(f'\n📥 Importing data to {TARGET_DATABASE} database (group_id: {TARGET_GROUP_ID})...')

        id_mapping = {}

        with driver.session(database=TARGET_DATABASE) as session:
            # Create nodes
            for node in nodes:
                old_id = node['old_id']
                labels = node['labels']
                props = dict(node['props'])

                # Update group_id
                props['group_id'] = TARGET_GROUP_ID

                # Get the uuid if it exists (for tracking)
                node_uuid = props.get('uuid', old_id)

                # Build labels string
                labels_str = ':'.join(labels)

                # Create node
                result = session.run(
                    f"""
                    CREATE (n:{labels_str})
                    SET n = $props
                    RETURN id(n) as new_id, n.uuid as uuid
                """,
                    props=props,
                )

                record = result.single()
                id_mapping[old_id] = record['new_id']

            print(f'   ✅ Created {len(nodes)} nodes')

            # Create relationships
            rel_count = 0
            for rel in relationships:
                from_old_id = rel['from_id']
                to_old_id = rel['to_id']
                rel_type = rel['rel_type']
                props = dict(rel['props']) if rel['props'] else {}

                # Update group_id in relationship properties if it exists
                if 'group_id' in props:
                    props['group_id'] = TARGET_GROUP_ID

                # Get new node IDs
                from_new_id = id_mapping.get(from_old_id)
                to_new_id = id_mapping.get(to_old_id)

                if from_new_id is None or to_new_id is None:
                    print(f'   ⚠️  Skipping relationship: node mapping not found')
                    continue

                # Create relationship
                session.run(
                    f"""
                    MATCH (a), (b)
                    WHERE id(a) = $from_id AND id(b) = $to_id
                    CREATE (a)-[r:{rel_type}]->(b)
                    SET r = $props
                """,
                    from_id=from_new_id,
                    to_id=to_new_id,
                    props=props,
                )

                rel_count += 1

            print(f'   ✅ Created {rel_count} relationships')

        # Step 3: Verify migration
        print(f'\n✅ Migration complete!')
        print(f'\n📊 Verification:')

        with driver.session(database=TARGET_DATABASE) as session:
            # Count nodes in target
            result = session.run(
                """
                MATCH (n {group_id: $group_id})
                RETURN count(n) as node_count
            """,
                group_id=TARGET_GROUP_ID,
            )

            target_count = result.single()['node_count']
            print(
                f'   Target database now has {target_count} nodes with group_id={TARGET_GROUP_ID}'
            )

            # Show node types
            result = session.run(
                """
                MATCH (n {group_id: $group_id})
                RETURN labels(n) as labels, count(*) as count
                ORDER BY count DESC
            """,
                group_id=TARGET_GROUP_ID,
            )

            print(f'\n   Node types:')
            for record in result:
                labels = ':'.join(record['labels'])
                count = record['count']
                print(f'      {labels}: {count}')

        print(f'\n🎉 Done! Your data has been migrated successfully.')
        print(f'\nNext steps:')
        print(f'1. Verify the data in Neo4j Browser:')
        print(f'   :use graphiti')
        print(f"   MATCH (n {{group_id: '{TARGET_GROUP_ID}'}}) RETURN n LIMIT 25")
        print(f'2. Test in LibreChat to ensure everything works')
        print(f'3. Once verified, you can delete the old data:')
        print(f'   :use neo4j')
        print(f"   MATCH (n {{group_id: '{SOURCE_GROUP_ID}'}}) DETACH DELETE n")

    finally:
        driver.close()


if __name__ == '__main__':
    print('=' * 70)
    print('Graphiti Data Migration Script')
    print('=' * 70)
    print(f"\nSource: {SOURCE_DATABASE} database, group_id='{SOURCE_GROUP_ID}'")
    print(f"Target: {TARGET_DATABASE} database, group_id='{TARGET_GROUP_ID}'")
    print(f'\nNeo4j URI: {NEO4J_URI}')
    print('=' * 70)

    response = input("\n⚠️  Ready to migrate? This will copy all data. Type 'yes' to continue: ")

    if response.lower() == 'yes':
        migrate_data()
    else:
        print('\n❌ Migration cancelled.')
