#!/usr/bin/env python3
"""
Test Phase 1: Database Schema Updates for DeepFace Migration

This test verifies that:
1. Database schema includes new DeepFace columns
2. Method signatures accept new parameters
3. Data can be inserted with DeepFace-specific fields
"""

import os
import sys
import sqlite3
import tempfile
from pathlib import Path

# Add parent directory to path
sys.path.insert(0, str(Path(__file__).parent.parent))

from src.core.database import DatabaseManager
from src.core.config import (
    DEEPFACE_DETECTOR_BACKEND, 
    DEEPFACE_MODEL_NAME,
    DEFAULT_FACE_TOLERANCE,
    DEEPFACE_SIMILARITY_THRESHOLD
)


def test_schema_has_deepface_columns():
    """Test that database schema includes DeepFace columns"""
    print("\n🧪 Test 1: Verify schema has DeepFace columns")
    
    # Create temporary database
    with tempfile.NamedTemporaryFile(delete=False, suffix='.db') as tmp:
        tmp_db_path = tmp.name
    
    try:
        # Initialize database
        db = DatabaseManager(tmp_db_path, verbose=0)
        
        # Connect and check schema
        conn = sqlite3.connect(tmp_db_path)
        cursor = conn.cursor()
        
        # Check faces table
        cursor.execute("PRAGMA table_info(faces)")
        faces_columns = {row[1]: row[2] for row in cursor.fetchall()}
        
        required_columns = {
            'detector_backend': 'TEXT',
            'model_name': 'TEXT',
            'face_confidence': 'REAL'
        }
        
        print("   Checking 'faces' table columns:")
        for col_name, col_type in required_columns.items():
            if col_name in faces_columns:
                print(f"      ✓ {col_name} ({faces_columns[col_name]})")
            else:
                print(f"      ❌ {col_name} - MISSING!")
                return False
        
        # Check person_encodings table
        cursor.execute("PRAGMA table_info(person_encodings)")
        pe_columns = {row[1]: row[2] for row in cursor.fetchall()}
        
        required_pe_columns = {
            'detector_backend': 'TEXT',
            'model_name': 'TEXT'
        }
        
        print("   Checking 'person_encodings' table columns:")
        for col_name, col_type in required_pe_columns.items():
            if col_name in pe_columns:
                print(f"      ✓ {col_name} ({pe_columns[col_name]})")
            else:
                print(f"      ❌ {col_name} - MISSING!")
                return False
        
        conn.close()
        print("   ✅ All schema columns present")
        return True
        
    finally:
        # Cleanup
        if os.path.exists(tmp_db_path):
            os.unlink(tmp_db_path)


def test_add_face_with_deepface_params():
    """Test that add_face() accepts DeepFace parameters"""
    print("\n🧪 Test 2: Test add_face() with DeepFace parameters")
    
    # Create temporary database
    with tempfile.NamedTemporaryFile(delete=False, suffix='.db') as tmp:
        tmp_db_path = tmp.name
    
    try:
        # Initialize database
        db = DatabaseManager(tmp_db_path, verbose=0)
        
        # Add a test photo
        photo_id = db.add_photo(
            photo_path="/test/photo.jpg",
            filename="photo.jpg",
            date_taken="2025-10-16"
        )
        
        if not photo_id:
            print("   ❌ Failed to add photo")
            return False
        
        print(f"   ✓ Added test photo (ID: {photo_id})")
        
        # Create dummy 512-dimensional encoding (ArcFace)
        import numpy as np
        dummy_encoding = np.random.rand(512).astype(np.float64)
        encoding_bytes = dummy_encoding.tobytes()
        
        # Add face with DeepFace parameters
        face_id = db.add_face(
            photo_id=photo_id,
            encoding=encoding_bytes,
            location="{'x': 100, 'y': 150, 'w': 200, 'h': 200}",
            confidence=0.0,
            quality_score=0.85,
            person_id=None,
            detector_backend='retinaface',
            model_name='ArcFace',
            face_confidence=0.99
        )
        
        if not face_id:
            print("   ❌ Failed to add face")
            return False
        
        print(f"   ✓ Added face with DeepFace params (ID: {face_id})")
        
        # Verify data was stored correctly
        conn = sqlite3.connect(tmp_db_path)
        cursor = conn.cursor()
        cursor.execute('''
            SELECT detector_backend, model_name, face_confidence, quality_score
            FROM faces WHERE id = ?
        ''', (face_id,))
        
        result = cursor.fetchone()
        conn.close()
        
        if not result:
            print("   ❌ Face data not found in database")
            return False
        
        detector, model, face_conf, quality = result
        
        print(f"   ✓ Verified stored data:")
        print(f"      - detector_backend: {detector}")
        print(f"      - model_name: {model}")
        print(f"      - face_confidence: {face_conf}")
        print(f"      - quality_score: {quality}")
        
        if detector != 'retinaface' or model != 'ArcFace' or face_conf != 0.99:
            print("   ❌ Stored data doesn't match input")
            return False
        
        print("   ✅ add_face() works with DeepFace parameters")
        return True
        
    finally:
        # Cleanup
        if os.path.exists(tmp_db_path):
            os.unlink(tmp_db_path)


def test_add_person_encoding_with_deepface_params():
    """Test that add_person_encoding() accepts DeepFace parameters"""
    print("\n🧪 Test 3: Test add_person_encoding() with DeepFace parameters")
    
    # Create temporary database
    with tempfile.NamedTemporaryFile(delete=False, suffix='.db') as tmp:
        tmp_db_path = tmp.name
    
    try:
        # Initialize database
        db = DatabaseManager(tmp_db_path, verbose=0)
        
        # Add a test person
        person_id = db.add_person(
            first_name="Test",
            last_name="Person",
            middle_name="",
            maiden_name="",
            date_of_birth=""
        )
        
        print(f"   ✓ Added test person (ID: {person_id})")
        
        # Add a test photo and face
        photo_id = db.add_photo("/test/photo.jpg", "photo.jpg")
        
        import numpy as np
        dummy_encoding = np.random.rand(512).astype(np.float64)
        encoding_bytes = dummy_encoding.tobytes()
        
        face_id = db.add_face(
            photo_id=photo_id,
            encoding=encoding_bytes,
            location="{'x': 100, 'y': 150, 'w': 200, 'h': 200}",
            quality_score=0.85,
            detector_backend='retinaface',
            model_name='ArcFace'
        )
        
        print(f"   ✓ Added test face (ID: {face_id})")
        
        # Add person encoding with DeepFace parameters
        db.add_person_encoding(
            person_id=person_id,
            face_id=face_id,
            encoding=encoding_bytes,
            quality_score=0.85,
            detector_backend='retinaface',
            model_name='ArcFace'
        )
        
        # Verify data was stored
        conn = sqlite3.connect(tmp_db_path)
        cursor = conn.cursor()
        cursor.execute('''
            SELECT detector_backend, model_name, quality_score
            FROM person_encodings WHERE person_id = ? AND face_id = ?
        ''', (person_id, face_id))
        
        result = cursor.fetchone()
        conn.close()
        
        if not result:
            print("   ❌ Person encoding not found in database")
            return False
        
        detector, model, quality = result
        
        print(f"   ✓ Verified stored data:")
        print(f"      - detector_backend: {detector}")
        print(f"      - model_name: {model}")
        print(f"      - quality_score: {quality}")
        
        if detector != 'retinaface' or model != 'ArcFace':
            print("   ❌ Stored data doesn't match input")
            return False
        
        print("   ✅ add_person_encoding() works with DeepFace parameters")
        return True
        
    finally:
        # Cleanup
        if os.path.exists(tmp_db_path):
            os.unlink(tmp_db_path)


def test_config_constants():
    """Test that config.py has DeepFace constants"""
    print("\n🧪 Test 4: Verify DeepFace configuration constants")
    
    print(f"   ✓ DEEPFACE_DETECTOR_BACKEND = {DEEPFACE_DETECTOR_BACKEND}")
    print(f"   ✓ DEEPFACE_MODEL_NAME = {DEEPFACE_MODEL_NAME}")
    print(f"   ✓ DEFAULT_FACE_TOLERANCE = {DEFAULT_FACE_TOLERANCE}")
    print(f"   ✓ DEEPFACE_SIMILARITY_THRESHOLD = {DEEPFACE_SIMILARITY_THRESHOLD}")
    
    if DEEPFACE_DETECTOR_BACKEND != 'retinaface':
        print(f"   ⚠️  Warning: Expected detector 'retinaface', got '{DEEPFACE_DETECTOR_BACKEND}'")
    
    if DEEPFACE_MODEL_NAME != 'ArcFace':
        print(f"   ⚠️  Warning: Expected model 'ArcFace', got '{DEEPFACE_MODEL_NAME}'")
    
    if DEFAULT_FACE_TOLERANCE != 0.4:
        print(f"   ⚠️  Warning: Expected tolerance 0.4, got {DEFAULT_FACE_TOLERANCE}")
    
    print("   ✅ Configuration constants loaded")
    return True


def run_all_tests():
    """Run all Phase 1 tests"""
    print("=" * 70)
    print("Phase 1 Schema Tests - DeepFace Migration")
    print("=" * 70)
    
    tests = [
        ("Schema Columns", test_schema_has_deepface_columns),
        ("add_face() Method", test_add_face_with_deepface_params),
        ("add_person_encoding() Method", test_add_person_encoding_with_deepface_params),
        ("Config Constants", test_config_constants)
    ]
    
    results = []
    for test_name, test_func in tests:
        try:
            result = test_func()
            results.append((test_name, result))
        except Exception as e:
            print(f"   ❌ Test failed with exception: {e}")
            import traceback
            traceback.print_exc()
            results.append((test_name, False))
    
    print("\n" + "=" * 70)
    print("Test Results Summary")
    print("=" * 70)
    
    for test_name, result in results:
        status = "✅ PASS" if result else "❌ FAIL"
        print(f"  {status}: {test_name}")
    
    passed = sum(1 for _, result in results if result)
    total = len(results)
    
    print()
    print(f"Tests passed: {passed}/{total}")
    print("=" * 70)
    
    return all(result for _, result in results)


if __name__ == "__main__":
    success = run_all_tests()
    sys.exit(0 if success else 1)


