import Foundation
import Testing

@testable import NucleicCore

@Suite("MoveLog — Smart Move diagnostics file")
struct MoveLogTests {
    /// A fresh temp directory to act as the log base, cleaned up by the caller.
    private func tempDir() -> URL {
        let dir = URL(fileURLWithPath: (NSTemporaryDirectory() as NSString)
            .appendingPathComponent("nucleic-movelog-\(UUID().uuidString)"))
        try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
        return dir
    }

    @Test func disabledLoggerIsACheapNoOp() {
        let dir = tempDir()
        defer { try? FileManager.default.removeItem(at: dir) }

        let log = MoveLog(label: "x", directory: dir, enabled: false)
        #expect(!log.isEnabled)
        #expect(log.fileURL == nil)
        // Calling through must be safe and must not create a file.
        log.line("should not be written")
        log.finish("noop")
        #expect(!FileManager.default.fileExists(atPath: dir.appendingPathComponent("SmartMove.log").path))
    }

    @Test func enabledLoggerWritesTaggedTimestampedLines() throws {
        let dir = tempDir()
        defer { try? FileManager.default.removeItem(at: dir) }

        let log = MoveLog(label: "move demo", directory: dir, enabled: true)
        #expect(log.isEnabled)
        log.line("phase: Copying files")
        log.finish("moved")

        let url = try #require(log.fileURL)
        let contents = try String(contentsOf: url, encoding: .utf8)
        #expect(contents.contains("move “move demo” started"))   // header
        #expect(contents.contains("[move demo] phase: Copying files"))
        #expect(contents.contains("finished: moved"))            // footer
    }

    @Test func finishClosesSoLaterLinesAreDropped() throws {
        let dir = tempDir()
        defer { try? FileManager.default.removeItem(at: dir) }

        let log = MoveLog(label: "x", directory: dir, enabled: true)
        log.line("before finish")
        log.finish("done")
        let url = try #require(log.fileURL)
        let afterFinish = try String(contentsOf: url, encoding: .utf8)

        log.line("THIS MUST NOT APPEAR")
        let afterLateLine = try String(contentsOf: url, encoding: .utf8)
        #expect(afterFinish == afterLateLine)
        #expect(!afterLateLine.contains("THIS MUST NOT APPEAR"))
    }

    @Test func rotatesAnOversizedLog() throws {
        let dir = tempDir()
        defer { try? FileManager.default.removeItem(at: dir) }
        let fm = FileManager.default

        // Seed an over-2MB existing log; opening a new run should roll it to SmartMove.previous.log.
        let existing = dir.appendingPathComponent("SmartMove.log")
        try Data(repeating: 0x20, count: 2_100_000).write(to: existing)

        let log = MoveLog(label: "x", directory: dir, enabled: true)
        log.finish("done")

        #expect(fm.fileExists(atPath: dir.appendingPathComponent("SmartMove.previous.log").path))
        // The new active log is the small fresh one (header + footer only), not the 2MB seed.
        let size = (try fm.attributesOfItem(atPath: existing.path)[.size] as? Int) ?? 0
        #expect(size < 2_000_000)
    }
}

@Suite("MoveProgress — canceling flag")
struct MoveProgressTests {
    @Test func cancelingDefaultsFalseAndIsPartOfEquality() {
        let working = MoveProgress(fraction: 0.5, phase: "Copying files…",
                                   updatedAt: Date(timeIntervalSince1970: 1))
        #expect(!working.canceling)

        let canceling = MoveProgress(fraction: 0.5, phase: "Canceling…",
                                     updatedAt: Date(timeIntervalSince1970: 1), canceling: true)
        #expect(canceling.canceling)
        #expect(working != canceling)
    }
}
