import CoreGraphics
@testable import peekaboo
import Testing

@Suite("Models Tests", .tags(.models, .unit))
struct ModelsTests {
    // MARK: - Enum Tests

    @Test("CaptureMode enum values and parsing", .tags(.fast))
    func captureMode() {
        // Test CaptureMode enum values
        #expect(CaptureMode.screen.rawValue == "screen")
        #expect(CaptureMode.window.rawValue == "window")
        #expect(CaptureMode.multi.rawValue == "multi")

        // Test CaptureMode from string
        #expect(CaptureMode(rawValue: "screen") == .screen)
        #expect(CaptureMode(rawValue: "window") == .window)
        #expect(CaptureMode(rawValue: "multi") == .multi)
        #expect(CaptureMode(rawValue: "invalid") == nil)
    }

    @Test("ImageFormat enum values and parsing", .tags(.fast))
    func imageFormat() {
        // Test ImageFormat enum values
        #expect(ImageFormat.png.rawValue == "png")
        #expect(ImageFormat.jpg.rawValue == "jpg")

        // Test ImageFormat from string
        #expect(ImageFormat(rawValue: "png") == .png)
        #expect(ImageFormat(rawValue: "jpg") == .jpg)
        #expect(ImageFormat(rawValue: "invalid") == nil)
    }

    @Test("CaptureFocus enum values and parsing", .tags(.fast))
    func captureFocus() {
        // Test CaptureFocus enum values
        #expect(CaptureFocus.background.rawValue == "background")
        #expect(CaptureFocus.foreground.rawValue == "foreground")

        // Test CaptureFocus from string
        #expect(CaptureFocus(rawValue: "background") == .background)
        #expect(CaptureFocus(rawValue: "foreground") == .foreground)
        #expect(CaptureFocus(rawValue: "invalid") == nil)
    }

    @Test("WindowDetailOption enum values and parsing", .tags(.fast))
    func windowDetailOption() {
        // Test WindowDetailOption enum values
        #expect(WindowDetailOption.off_screen.rawValue == "off_screen")
        #expect(WindowDetailOption.bounds.rawValue == "bounds")
        #expect(WindowDetailOption.ids.rawValue == "ids")

        // Test WindowDetailOption from string
        #expect(WindowDetailOption(rawValue: "off_screen") == .off_screen)
        #expect(WindowDetailOption(rawValue: "bounds") == .bounds)
        #expect(WindowDetailOption(rawValue: "ids") == .ids)
        #expect(WindowDetailOption(rawValue: "invalid") == nil)
    }

    // MARK: - Parameterized Enum Tests

    @Test("CaptureMode raw values are valid", .tags(.fast))
    func captureModeRawValuesValid() {
        let validValues = ["screen", "window", "multi"]
        for rawValue in validValues {
            #expect(CaptureMode(rawValue: rawValue) != nil)
        }
    }

    @Test("ImageFormat raw values are valid", .tags(.fast))
    func imageFormatRawValuesValid() {
        let validValues = ["png", "jpg"]
        for rawValue in validValues {
            #expect(ImageFormat(rawValue: rawValue) != nil)
        }
    }

    @Test("CaptureFocus raw values are valid", .tags(.fast))
    func captureFocusRawValuesValid() {
        let validValues = ["background", "foreground"]
        for rawValue in validValues {
            #expect(CaptureFocus(rawValue: rawValue) != nil)
        }
    }

    // MARK: - Model Structure Tests

    @Test("WindowBounds initialization and properties", .tags(.fast))
    func windowBounds() {
        let bounds = WindowBounds(xCoordinate: 100, yCoordinate: 200, width: 1200, height: 800)

        #expect(bounds.xCoordinate == 100)
        #expect(bounds.yCoordinate == 200)
        #expect(bounds.width == 1200)
        #expect(bounds.height == 800)
    }

    @Test("SavedFile with all properties", .tags(.fast))
    func savedFile() {
        let savedFile = SavedFile(
            path: "/tmp/test.png",
            item_label: "Screen 1",
            window_title: "Safari - Main Window",
            window_id: 12345,
            window_index: 0,
            mime_type: "image/png"
        )

        #expect(savedFile.path == "/tmp/test.png")
        #expect(savedFile.item_label == "Screen 1")
        #expect(savedFile.window_title == "Safari - Main Window")
        #expect(savedFile.window_id == 12345)
        #expect(savedFile.window_index == 0)
        #expect(savedFile.mime_type == "image/png")
    }

    @Test("SavedFile with nil optional values", .tags(.fast))
    func savedFileWithNilValues() {
        let savedFile = SavedFile(
            path: "/tmp/screen.png",
            item_label: nil,
            window_title: nil,
            window_id: nil,
            window_index: nil,
            mime_type: "image/png"
        )

        #expect(savedFile.path == "/tmp/screen.png")
        #expect(savedFile.item_label == nil)
        #expect(savedFile.window_title == nil)
        #expect(savedFile.window_id == nil)
        #expect(savedFile.window_index == nil)
        #expect(savedFile.mime_type == "image/png")
    }

    @Test("ApplicationInfo initialization", .tags(.fast))
    func applicationInfo() {
        let appInfo = ApplicationInfo(
            app_name: "Safari",
            bundle_id: "com.apple.Safari",
            pid: 1234,
            is_active: true,
            window_count: 2
        )

        #expect(appInfo.app_name == "Safari")
        #expect(appInfo.bundle_id == "com.apple.Safari")
        #expect(appInfo.pid == 1234)
        #expect(appInfo.is_active == true)
        #expect(appInfo.window_count == 2)
    }

    @Test("WindowInfo with bounds", .tags(.fast))
    func windowInfo() {
        let bounds = WindowBounds(xCoordinate: 100, yCoordinate: 100, width: 1200, height: 800)
        let windowInfo = WindowInfo(
            window_title: "Safari - Main Window",
            window_id: 12345,
            window_index: 0,
            bounds: bounds,
            is_on_screen: true
        )

        #expect(windowInfo.window_title == "Safari - Main Window")
        #expect(windowInfo.window_id == 12345)
        #expect(windowInfo.window_index == 0)
        #expect(windowInfo.bounds != nil)
        #expect(windowInfo.bounds?.xCoordinate == 100)
        #expect(windowInfo.bounds?.yCoordinate == 100)
        #expect(windowInfo.bounds?.width == 1200)
        #expect(windowInfo.bounds?.height == 800)
        #expect(windowInfo.is_on_screen == true)
    }

    @Test("TargetApplicationInfo", .tags(.fast))
    func targetApplicationInfo() {
        let targetApp = TargetApplicationInfo(
            app_name: "Safari",
            bundle_id: "com.apple.Safari",
            pid: 1234
        )

        #expect(targetApp.app_name == "Safari")
        #expect(targetApp.bundle_id == "com.apple.Safari")
        #expect(targetApp.pid == 1234)
    }

    // MARK: - Collection Data Tests

    @Test("ApplicationListData contains applications", .tags(.fast))
    func applicationListData() {
        let app1 = ApplicationInfo(
            app_name: "Safari",
            bundle_id: "com.apple.Safari",
            pid: 1234,
            is_active: true,
            window_count: 2
        )

        let app2 = ApplicationInfo(
            app_name: "Terminal",
            bundle_id: "com.apple.Terminal",
            pid: 5678,
            is_active: false,
            window_count: 1
        )

        let appListData = ApplicationListData(applications: [app1, app2])

        #expect(appListData.applications.count == 2)
        #expect(appListData.applications[0].app_name == "Safari")
        #expect(appListData.applications[1].app_name == "Terminal")
    }

    @Test("WindowListData with target application", .tags(.fast))
    func windowListData() {
        let bounds = WindowBounds(xCoordinate: 100, yCoordinate: 100, width: 1200, height: 800)
        let window = WindowInfo(
            window_title: "Safari - Main Window",
            window_id: 12345,
            window_index: 0,
            bounds: bounds,
            is_on_screen: true
        )

        let targetApp = TargetApplicationInfo(
            app_name: "Safari",
            bundle_id: "com.apple.Safari",
            pid: 1234
        )

        let windowListData = WindowListData(
            windows: [window],
            target_application_info: targetApp
        )

        #expect(windowListData.windows.count == 1)
        #expect(windowListData.windows[0].window_title == "Safari - Main Window")
        #expect(windowListData.target_application_info.app_name == "Safari")
        #expect(windowListData.target_application_info.bundle_id == "com.apple.Safari")
        #expect(windowListData.target_application_info.pid == 1234)
    }

    @Test("ImageCaptureData with saved files", .tags(.fast))
    func imageCaptureData() {
        let savedFile = SavedFile(
            path: "/tmp/test.png",
            item_label: "Screen 1",
            window_title: nil,
            window_id: nil,
            window_index: nil,
            mime_type: "image/png"
        )

        let imageData = ImageCaptureData(saved_files: [savedFile])

        #expect(imageData.saved_files.count == 1)
        #expect(imageData.saved_files[0].path == "/tmp/test.png")
        #expect(imageData.saved_files[0].item_label == "Screen 1")
        #expect(imageData.saved_files[0].mime_type == "image/png")
    }

    // MARK: - Error Tests

    @Test("CaptureError descriptions are user-friendly", .tags(.fast))
    func captureErrorDescriptions() {
        #expect(CaptureError.noDisplaysAvailable.errorDescription == "No displays available for capture.")
        #expect(CaptureError.screenRecordingPermissionDenied.errorDescription!
            .contains("Screen recording permission is required")
        )
        #expect(CaptureError.invalidDisplayID.errorDescription == "Invalid display ID provided.")
        #expect(CaptureError.captureCreationFailed.errorDescription == "Failed to create the screen capture.")
        #expect(CaptureError.windowNotFound.errorDescription == "The specified window could not be found.")
        #expect(CaptureError.windowCaptureFailed.errorDescription == "Failed to capture the specified window.")
        let fileError = CaptureError.fileWriteError("/tmp/test.png", nil)
        #expect(fileError.errorDescription?.starts(with: "Failed to write capture file to path: /tmp/test.png.") == true)
        #expect(CaptureError.appNotFound("Safari")
            .errorDescription == "Application with identifier 'Safari' not found or is not running."
        )
        #expect(CaptureError.invalidWindowIndex(5).errorDescription == "Invalid window index: 5.")
    }

    @Test("CaptureError exit codes", .tags(.fast))
    func captureErrorExitCodes() {
        let testCases: [(CaptureError, Int32)] = [
            (.noDisplaysAvailable, 10),
            (.screenRecordingPermissionDenied, 11),
            (.accessibilityPermissionDenied, 12),
            (.invalidDisplayID, 13),
            (.captureCreationFailed, 14),
            (.windowNotFound, 15),
            (.windowCaptureFailed, 16),
            (.fileWriteError("test", nil), 17),
            (.appNotFound("test"), 18),
            (.invalidWindowIndex(0), 19),
            (.invalidArgument("test"), 20),
            (.unknownError("test"), 1)
        ]

        for (error, expectedCode) in testCases {
            #expect(error.exitCode == expectedCode)
        }
    }

    // MARK: - WindowData Tests

    @Test("WindowData initialization from CGRect", .tags(.fast))
    func windowData() {
        let bounds = CGRect(x: 100, y: 200, width: 1200, height: 800)
        let windowData = WindowData(
            windowId: 12345,
            title: "Safari - Main Window",
            bounds: bounds,
            isOnScreen: true,
            windowIndex: 0
        )

        #expect(windowData.windowId == 12345)
        #expect(windowData.title == "Safari - Main Window")
        #expect(windowData.bounds.origin.x == 100)
        #expect(windowData.bounds.origin.y == 200)
        #expect(windowData.bounds.size.width == 1200)
        #expect(windowData.bounds.size.height == 800)
        #expect(windowData.isOnScreen == true)
        #expect(windowData.windowIndex == 0)
    }

    @Test("WindowSpecifier variants", .tags(.fast))
    func windowSpecifier() {
        let titleSpecifier = WindowSpecifier.title("Main Window")
        let indexSpecifier = WindowSpecifier.index(0)

        switch titleSpecifier {
        case let .title(title):
            #expect(title == "Main Window")
        case .index:
            Issue.record("Expected title specifier")
        }

        switch indexSpecifier {
        case .title:
            Issue.record("Expected index specifier")
        case let .index(index):
            #expect(index == 0)
        }
    }
}

// MARK: - Extended Model Tests

@Suite("Model Edge Cases", .tags(.models, .unit))
struct ModelEdgeCaseTests {
    @Test(
        "WindowBounds with edge values",
        arguments: [
            (x: 0, y: 0, width: 0, height: 0),
            (x: -100, y: -100, width: 100, height: 100),
            (x: Int.max, y: Int.max, width: 1, height: 1)
        ]
    )
    func windowBoundsEdgeCases(x xCoordinate: Int, y yCoordinate: Int, width: Int, height: Int) {
        let bounds = WindowBounds(xCoordinate: xCoordinate, yCoordinate: yCoordinate, width: width, height: height)
        #expect(bounds.xCoordinate == xCoordinate)
        #expect(bounds.yCoordinate == yCoordinate)
        #expect(bounds.width == width)
        #expect(bounds.height == height)
    }

    @Test("ApplicationInfo with extreme values", .tags(.fast))
    func applicationInfoExtremeValues() {
        let appInfo = ApplicationInfo(
            app_name: String(repeating: "A", count: 1000),
            bundle_id: String(repeating: "com.test.", count: 100),
            pid: Int32.max,
            is_active: true,
            window_count: Int.max
        )

        #expect(appInfo.app_name.count == 1000)
        #expect(appInfo.bundle_id.contains("com.test."))
        #expect(appInfo.pid == Int32.max)
        #expect(appInfo.window_count == Int.max)
    }

    @Test(
        "SavedFile path validation",
        arguments: [
            "/tmp/test.png",
            "/Users/test/Desktop/screenshot.jpg",
            "~/Documents/capture.png",
            "./relative/path/image.png",
            "/path with spaces/image.png",
            "/path/with/特殊文字.png"
        ]
    )
    func savedFilePathValidation(path: String) {
        let savedFile = SavedFile(
            path: path,
            item_label: nil,
            window_title: nil,
            window_id: nil,
            window_index: nil,
            mime_type: "image/png"
        )

        #expect(savedFile.path == path)
        #expect(!savedFile.path.isEmpty)
    }

    @Test(
        "MIME type validation",
        arguments: ["image/png", "image/jpeg", "image/jpg"]
    )
    func mimeTypeValidation(mimeType: String) {
        let savedFile = SavedFile(
            path: "/tmp/test",
            item_label: nil,
            window_title: nil,
            window_id: nil,
            window_index: nil,
            mime_type: mimeType
        )

        #expect(savedFile.mime_type == mimeType)
        #expect(savedFile.mime_type.starts(with: "image/"))
    }
}
