import XCTest
import AppKit
@testable import PoseCore
@testable import PoseReview

final class PhotoViewportTests: XCTestCase {
    func testFitsOffCenterRiderAndBikeWithMargin() {
        let panel = PixelRect(x: 100, y: 50, width: 1800, height: 1100)
        let target = PixelRect(x: 1200, y: 300, width: 450, height: 500)
        let layout = PhotoViewport(panel: panel, region: target, viewport: CGSize(width: 600, height: 400), zoom: nil)
        XCTAssertGreaterThan(layout.zoom, 1)
        let visible = layout.visibleRect(center: layout.targetCenter)
        XCTAssertLessThanOrEqual(visible.minX, target.x)
        XCTAssertGreaterThanOrEqual(visible.maxX, target.x + target.width)
        XCTAssertLessThanOrEqual(visible.minY, target.y)
        XCTAssertGreaterThanOrEqual(visible.maxY, target.y + target.height)
        XCTAssertEqual(visible.midX, target.x + target.width / 2, accuracy: 0.001)
        XCTAssertEqual(visible.midY, target.y + target.height / 2, accuracy: 0.001)
    }
    func testEdgeRiderRemainsCenteredWithEmptyMargin() {
        let panel = PixelRect(x: 0, y: 0, width: 1750, height: 1050)
        let target = PixelRect(x: 1160, y: 295, width: 465, height: 525)
        let layout = PhotoViewport(panel: panel, region: target, viewport: CGSize(width: 700, height: 350), zoom: nil)
        let visible = layout.visibleRect(center: layout.targetCenter)
        XCTAssertEqual(visible.midX, target.x + target.width / 2, accuracy: 0.001)
        XCTAssertEqual(visible.midY, target.y + target.height / 2, accuracy: 0.001)
        XCTAssertTrue(visible.contains(CGRect(x: target.x, y: target.y, width: target.width, height: target.height)))
    }
    func testPhotoFallbackAndResizeKeepWholeTarget() {
        let panel = PixelRect(x: 0, y: 0, width: 1800, height: 1100)
        let full = PhotoViewport(panel: panel, region: nil, viewport: CGSize(width: 450, height: 600), zoom: nil)
        XCTAssertEqual(full.zoom, 1)
        for size in [CGSize(width: 350, height: 600), CGSize(width: 1000, height: 260)] {
            let target = PixelRect(x: 1200, y: 250, width: 500, height: 600)
            let layout = PhotoViewport(panel: panel, region: target, viewport: size, zoom: nil)
            let visible = layout.visibleRect(center: layout.targetCenter)
            XCTAssertTrue(visible.contains(CGRect(x: target.x, y: target.y, width: target.width, height: target.height)))
        }
    }
    @MainActor func testNativeScrollPreservesPanAndCoordinateMapping() {
        let view = PhotoScrollView(frame: NSRect(x: 0, y: 0, width: 500, height: 400))
        let model = ReviewerModel()
        let panel = PixelRect(x: 80, y: 60, width: 1800, height: 1100)
        let target = PixelRect(x: 1100, y: 200, width: 500, height: 600)
        view.configure(model: model, frameID: "rider", panel: panel, region: target)
        view.layoutSubtreeIfNeeded()
        let original = view.contentView.bounds.origin
        view.contentView.scroll(to: NSPoint(x: original.x - 20, y: original.y + 10))
        let panned = view.contentView.bounds.origin
        view.configure(model: model, frameID: "rider", panel: panel, region: target)
        view.layoutSubtreeIfNeeded()
        XCTAssertEqual(view.contentView.bounds.origin, panned)
        let source = Point2(x: target.x + 200, y: target.y + 100)
        let display = ReviewCoordinates.display(source, panel: panel, scale: view.canvas.scale)
        let clipPoint = view.canvas.convert(NSPoint(x: display.x, y: display.y), to: view.contentView)
        let back = view.canvas.convert(clipPoint, from: view.contentView)
        let recovered = ReviewCoordinates.source(Point2(x: back.x, y: back.y), panel: panel, scale: view.canvas.scale)
        XCTAssertEqual(recovered.x, source.x, accuracy: 0.001)
        XCTAssertEqual(recovered.y, source.y, accuracy: 0.001)
        var settings = model.settings("rider"); settings.autoFrame = false; settings.zoom = 1; settings.framingRequest += 1
        model.setSettings("rider", settings)
        view.configure(model: model, frameID: "rider", panel: panel, region: target)
        view.layoutSubtreeIfNeeded()
        XCTAssertEqual(view.currentZoom, 1)
    }
}
