import XCTest
@testable import MixBoard

final class WaveformGeneratorTests: XCTestCase {

    // MARK: - WaveformSample Codable

    func testWaveformSampleCodable() throws {
        let sample = WaveformGenerator.WaveformSample(min: -0.5, max: 0.8)
        let data = try JSONEncoder().encode(sample)
        let decoded = try JSONDecoder().decode(WaveformGenerator.WaveformSample.self, from: data)
        XCTAssertEqual(decoded.min, -0.5, accuracy: 0.001)
        XCTAssertEqual(decoded.max, 0.8, accuracy: 0.001)
    }

    func testWaveformSampleArrayCodable() throws {
        let samples = [
            WaveformGenerator.WaveformSample(min: -1.0, max: 1.0),
            WaveformGenerator.WaveformSample(min: -0.3, max: 0.5),
            WaveformGenerator.WaveformSample(min: 0.0, max: 0.0),
        ]
        let data = try JSONEncoder().encode(samples)
        let decoded = try JSONDecoder().decode([WaveformGenerator.WaveformSample].self, from: data)
        XCTAssertEqual(decoded.count, 3)
        XCTAssertEqual(decoded[0].min, -1.0, accuracy: 0.001)
        XCTAssertEqual(decoded[1].max, 0.5, accuracy: 0.001)
        XCTAssertEqual(decoded[2].min, 0.0, accuracy: 0.001)
    }

    // MARK: - decodeCachedWaveform

    func testDecodeCachedWaveformValid() throws {
        let samples = [
            WaveformGenerator.WaveformSample(min: -0.7, max: 0.9),
            WaveformGenerator.WaveformSample(min: -0.2, max: 0.4),
        ]
        let data = try JSONEncoder().encode(samples)
        let decoded = WaveformGenerator.decodeCachedWaveform(from: data)
        XCTAssertNotNil(decoded)
        XCTAssertEqual(decoded?.count, 2)
        XCTAssertEqual(decoded![0].min, Float(-0.7), accuracy: Float(0.001))
        XCTAssertEqual(decoded![1].max, Float(0.4), accuracy: Float(0.001))
    }

    func testDecodeCachedWaveformInvalidData() {
        let garbage = Data([0x00, 0x01, 0xFF, 0xDE, 0xAD])
        let decoded = WaveformGenerator.decodeCachedWaveform(from: garbage)
        XCTAssertNil(decoded)
    }

    func testDecodeCachedWaveformEmptyArray() throws {
        let data = try JSONEncoder().encode([WaveformGenerator.WaveformSample]())
        let decoded = WaveformGenerator.decodeCachedWaveform(from: data)
        XCTAssertNotNil(decoded)
        XCTAssertEqual(decoded?.count, 0)
    }

    func testDecodeCachedWaveformEmptyData() {
        let decoded = WaveformGenerator.decodeCachedWaveform(from: Data())
        XCTAssertNil(decoded)
    }

    // MARK: - generateWaveform (error path — non-existent file)

    func testGenerateWaveformNonExistentFile() async {
        let track = Track(title: "Missing", filePath: "nonexistent/path/missing.mp3")
        do {
            _ = try await WaveformGenerator.generateWaveform(for: track)
            XCTFail("Expected an error for a non-existent file")
        } catch {
            // Expected — file not found
        }
    }

    // MARK: - WaveformSample values

    func testWaveformSampleNegativeValues() throws {
        let sample = WaveformGenerator.WaveformSample(min: -1.0, max: -0.1)
        let data = try JSONEncoder().encode(sample)
        let decoded = try JSONDecoder().decode(WaveformGenerator.WaveformSample.self, from: data)
        XCTAssertEqual(decoded.min, -1.0, accuracy: 0.001)
        XCTAssertEqual(decoded.max, -0.1, accuracy: 0.001)
    }

    func testWaveformSampleExtremeValues() throws {
        let sample = WaveformGenerator.WaveformSample(min: -Float.greatestFiniteMagnitude, max: Float.greatestFiniteMagnitude)
        let data = try JSONEncoder().encode(sample)
        let decoded = try JSONDecoder().decode(WaveformGenerator.WaveformSample.self, from: data)
        XCTAssertEqual(decoded.min, -Float.greatestFiniteMagnitude, accuracy: 1)
        XCTAssertEqual(decoded.max, Float.greatestFiniteMagnitude, accuracy: 1)
    }
}
