//
//  TestDBFactory.swift
//  DailyNotificationPluginTests
//
//  Created by Matthew Raymer on 2025-12-16
//  Copyright © 2025 TimeSafari. All rights reserved.
//

import Foundation
import SQLite3
@testable import DailyNotificationPlugin

/**
 * Test database factory for recovery testing
 * 
 * Provides utilities to create test databases with intentionally invalid/corrupt data
 * for testing recovery scenarios.
 */
class TestDBFactory {
    
    /**
     * Create a clean test database
     * 
     * @return Tuple of (database, path)
     */
    static func createCleanDatabase() -> (DailyNotificationDatabase, String) {
        let testDbPath = NSTemporaryDirectory().appending("test_recovery_db_\(UUID().uuidString).sqlite")
        let database = DailyNotificationDatabase(path: testDbPath)
        return (database, testDbPath)
    }
    
    /**
     * Inject invalid notification record directly into database
     * 
     * @param database Database instance
     * @param id Notification ID (can be empty for invalid test)
     * @param scheduledTime Scheduled time (can be invalid/negative)
     * @param payloadJSON Payload (can be invalid JSON)
     */
    static func injectInvalidNotificationRecord(
        database: DailyNotificationDatabase,
        id: String = "",
        scheduledTime: Int64 = -1,
        payloadJSON: String = "invalid json {"
    ) {
        // Direct SQL injection for testing (using executeSQL which is public)
        let escapedId = id.replacingOccurrences(of: "'", with: "''")
        let escapedPayload = payloadJSON.replacingOccurrences(of: "'", with: "''")
        let sql = """
            INSERT INTO \(DailyNotificationDatabase.TABLE_NOTIF_CONTENTS) (
                \(DailyNotificationDatabase.COL_CONTENTS_SLOT_ID),
                \(DailyNotificationDatabase.COL_CONTENTS_PAYLOAD_JSON),
                \(DailyNotificationDatabase.COL_CONTENTS_FETCHED_AT),
                \(DailyNotificationDatabase.COL_CONTENTS_ETAG)
            ) VALUES ('\(escapedId)', '\(escapedPayload)', \(scheduledTime), NULL);
        """
        database.executeSQL(sql)
        print("TestDBFactory: Injected invalid notification record: id=\(id), time=\(scheduledTime)")
    }
    
    /**
     * Inject notification with null/empty required fields
     */
    static func injectNotificationWithNullFields(database: DailyNotificationDatabase) {
        let sql = """
            INSERT INTO \(DailyNotificationDatabase.TABLE_NOTIF_CONTENTS) (
                \(DailyNotificationDatabase.COL_CONTENTS_SLOT_ID),
                \(DailyNotificationDatabase.COL_CONTENTS_PAYLOAD_JSON),
                \(DailyNotificationDatabase.COL_CONTENTS_FETCHED_AT)
            ) VALUES (NULL, '', 0);
        """
        database.executeSQL(sql)
    }
    
    /**
     * Inject duplicate notification records (same ID, different times)
     */
    static func injectDuplicateNotifications(
        database: DailyNotificationDatabase,
        id: String,
        times: [Int64]
    ) {
        for time in times {
            injectInvalidNotificationRecord(
                database: database,
                id: id,
                scheduledTime: time,
                payloadJSON: "{\"title\":\"Test\",\"body\":\"Body\"}"
            )
        }
    }
    
    /**
     * Reset database (drop and recreate tables)
     */
    static func resetDatabase(database: DailyNotificationDatabase) {
        database.executeSQL("DROP TABLE IF EXISTS \(DailyNotificationDatabase.TABLE_NOTIF_CONTENTS);")
        database.executeSQL("DROP TABLE IF EXISTS \(DailyNotificationDatabase.TABLE_NOTIF_DELIVERIES);")
        database.executeSQL("DROP TABLE IF EXISTS \(DailyNotificationDatabase.TABLE_NOTIF_CONFIG);")
        // Recreate tables by opening a new connection
        let _ = DailyNotificationDatabase(path: database.getPath())
    }
    
    /**
     * Clean up test database file
     */
    static func cleanupDatabase(path: String) {
        let fileManager = FileManager.default
        if fileManager.fileExists(atPath: path) {
            try? fileManager.removeItem(atPath: path)
        }
    }
}


