"""
Test suite for onepasswd refactor - validates backward compatibility and new features.
"""
import os
import sys
import tempfile
import json
import shutil

# Add parent directory to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from onepasswd.models import PasswordEntry
from onepasswd.onepasswd import DB
from onepasswd import crypto


def test_password_entry_legacy():
    """Test PasswordEntry can load legacy v1 format."""
    print("Testing legacy v1 format loading...")
    
    legacy_data = {
        'entries': ['github', 'work'],
        'passwd': 'encrypted_pass_123',
        'time': '1234567890.123'
    }
    
    entry = PasswordEntry.from_dict(legacy_data)
    
    assert entry.entries == ['github', 'work']
    assert entry.passwd == 'encrypted_pass_123'
    assert entry.time == '1234567890.123'
    assert entry.version == 1
    assert entry.title is None
    assert entry.url is None
    
    print("✓ Legacy format loading works")


def test_password_entry_new():
    """Test PasswordEntry with v2 format."""
    print("Testing new v2 format...")
    
    new_data = {
        'entries': ['github', 'work'],
        'passwd': 'encrypted_pass_123',
        'time': '1234567890.123',
        'version': 2,
        'title': 'GitHub Work',
        'url': 'https://github.com',
        'username': 'user@example.com',
        'description': 'Work account',
        'tags': ['dev', 'work']
    }
    
    entry = PasswordEntry.from_dict(new_data)
    
    assert entry.entries == ['github', 'work']
    assert entry.version == 2
    assert entry.title == 'GitHub Work'
    assert entry.url == 'https://github.com'
    assert entry.username == 'user@example.com'
    assert entry.tags == ['dev', 'work']
    
    print("✓ New format loading works")


def test_password_entry_serialization():
    """Test PasswordEntry serialization only includes non-empty fields."""
    print("Testing serialization...")
    
    entry = PasswordEntry(
        entries=['test'],
        passwd='encrypted',
        title='Test Entry',
        url='https://example.com',
        username='',  # Empty - should not be saved
        description=None,  # None - should not be saved
        tags=[]  # Empty list - should not be saved
    )
    
    data = entry.to_dict()
    
    assert 'title' in data
    assert 'url' in data
    assert 'username' not in data  # Empty string
    assert 'description' not in data  # None
    assert 'tags' not in data  # Empty list
    assert data['version'] == 2
    
    print("✓ Serialization works correctly")


def test_password_entry_infer_metadata():
    """Test metadata inference from keywords."""
    print("Testing metadata inference...")
    
    # Test known service
    entry1 = PasswordEntry(entries=['github', 'work'], passwd='enc')
    title1, url1 = entry1.infer_metadata()
    assert title1 == 'Github'
    assert url1 == 'https://github.com'
    
    # Test domain-like keyword
    entry2 = PasswordEntry(entries=['example.com', 'test'], passwd='enc')
    title2, url2 = entry2.infer_metadata()
    assert title2 == 'Example.com'
    assert url2 == 'https://example.com'
    
    # Test with existing metadata
    entry3 = PasswordEntry(
        entries=['github'], 
        passwd='enc',
        title='My GitHub',
        url='https://github.com/login'
    )
    title3, url3 = entry3.infer_metadata()
    assert title3 == 'My GitHub'  # Use existing
    assert url3 == 'https://github.com/login'  # Use existing
    
    print("✓ Metadata inference works")


def test_db_backward_compatibility():
    """Test DB class handles both old and new data formats."""
    print("Testing DB backward compatibility...")
    
    with tempfile.TemporaryDirectory() as tmpdir:
        db_path = os.path.join(tmpdir, 'test.db')
        
        # Create DB with legacy data
        legacy_db = {
            'hash1': {
                'entries': ['github', 'work'],
                'passwd': 'encrypted1',
                'time': '123.456'
            }
        }
        
        with open(db_path, 'w') as f:
            json.dump(legacy_db, f)
        
        # Load with DB class
        db = DB(db_path)
        
        # Check legacy data loads
        assert ('github', 'work') in db
        assert db[('github', 'work')] == 'encrypted1'
        
        # Add new entry with rich data
        db[('gitlab', 'personal')] = {
            'passwd': 'encrypted2',
            'title': 'GitLab Personal',
            'url': 'https://gitlab.com',
            'username': 'user@example.com'
        }
        
        # Reload and check both exist
        db2 = DB(db_path)
        assert ('github', 'work') in db2
        assert ('gitlab', 'personal') in db2
        
        item = db2.get_item(('gitlab', 'personal'))
        assert item['version'] == 2
        assert item['title'] == 'GitLab Personal'
        
        print("✓ DB backward compatibility works")


def test_db_update_item():
    """Test DB.update_item() method."""
    print("Testing DB.update_item()...")
    
    with tempfile.TemporaryDirectory() as tmpdir:
        db_path = os.path.join(tmpdir, 'test.db')
        db = DB(db_path)
        
        # Add initial entry
        db[('test', 'entry')] = 'encrypted_pass'
        
        # Update with metadata
        db.update_item(
            ('test', 'entry'),
            title='Test Entry',
            url='https://test.com',
            username='user@test.com'
        )
        
        # Check update
        item = db.get_item(('test', 'entry'))
        assert item['title'] == 'Test Entry'
        assert item['url'] == 'https://test.com'
        assert item['username'] == 'user@test.com'
        assert item['version'] == 2
        assert 'modified_time' in item
        
        print("✓ DB.update_item() works")


def test_db_get_all_items():
    """Test DB.get_all_items() returns PasswordEntry objects."""
    print("Testing DB.get_all_items()...")
    
    with tempfile.TemporaryDirectory() as tmpdir:
        db_path = os.path.join(tmpdir, 'test.db')
        db = DB(db_path)
        
        # Add entries
        db[('entry1',)] = 'pass1'
        db[('entry2',)] = {'passwd': 'pass2', 'title': 'Entry 2'}
        
        # Get all items
        items = list(db.get_all_items())
        
        assert len(items) == 2
        assert all(isinstance(item, PasswordEntry) for item in items)
        
        # Check one has title, one doesn't
        titles = [item.title for item in items]
        assert 'Entry 2' in titles
        assert None in titles
        
        print("✓ DB.get_all_items() works")


def test_exporters():
    """Test exporters can handle PasswordEntry objects."""
    print("Testing exporters...")
    
    from onepasswd.exporters import ChromeExporter, AppleKeychainExporter, JSONExporter
    
    with tempfile.TemporaryDirectory() as tmpdir:
        # Create test entries
        entries = [
            PasswordEntry(
                entries=['github', 'work'],
                passwd=crypto.encrypt_passwd('password123', 'master'),
                title='GitHub',
                url='https://github.com',
                username='user@example.com'
            ),
            PasswordEntry(
                entries=['gitlab'],
                passwd=crypto.encrypt_passwd('password456', 'master'),
                # No title/url - should be inferred
            )
        ]
        
        # Test Chrome export
        chrome_path = os.path.join(tmpdir, 'chrome.csv')
        ChromeExporter().export(iter(entries), chrome_path, 'master')
        assert os.path.exists(chrome_path)
        
        with open(chrome_path) as f:
            content = f.read()
            assert 'GitHub' in content
            assert 'https://github.com' in content
            assert 'user@example.com' in content
            assert 'password123' in content
        
        # Test Apple export
        apple_path = os.path.join(tmpdir, 'apple.csv')
        AppleKeychainExporter().export(iter(entries), apple_path, 'master')
        assert os.path.exists(apple_path)
        
        # Test JSON export
        json_path = os.path.join(tmpdir, 'backup.json')
        JSONExporter().export(iter(entries), json_path, 'master')
        assert os.path.exists(json_path)
        
        with open(json_path) as f:
            data = json.load(f)
            assert len(data) == 2
            assert data[0]['title'] == 'GitHub'
            assert 'password_decrypted' in data[0]
        
        print("✓ Exporters work")


def run_all_tests():
    """Run all tests."""
    print("=" * 60)
    print("Running onepasswd refactor tests")
    print("=" * 60)
    print()
    
    try:
        test_password_entry_legacy()
        test_password_entry_new()
        test_password_entry_serialization()
        test_password_entry_infer_metadata()
        test_db_backward_compatibility()
        test_db_update_item()
        test_db_get_all_items()
        test_exporters()
        
        print()
        print("=" * 60)
        print("✅ All tests passed!")
        print("=" * 60)
        return 0
        
    except AssertionError as e:
        print()
        print("=" * 60)
        print(f"❌ Test failed: {e}")
        print("=" * 60)
        import traceback
        traceback.print_exc()
        return 1
    except Exception as e:
        print()
        print("=" * 60)
        print(f"❌ Error: {e}")
        print("=" * 60)
        import traceback
        traceback.print_exc()
        return 1


if __name__ == '__main__':
    sys.exit(run_all_tests())
