import Foundation

/// URL protocol that intercepts Chad Music API requests and returns canned responses.
/// Activated only when `-MockNetwork` launch argument is present.
final class MockURLProtocol: URLProtocol {
    /// Map of URL path suffixes to (statusCode, responseData)
    static var mockResponses: [String: (Int, Data)] = [:]

    static func registerMockResponses() {
        let stats = """
        {"tracks":1234,"albums":56,"artists":78,"duration":"3d 12h"}
        """

        let categories = """
        [{"item":"Rock","count":42},{"item":"Jazz","count":15},{"item":"Electronic","count":30}]
        """

        let years = """
        [{"item":2024,"count":12},{"item":2023,"count":18},{"item":2012,"count":5}]
        """

        let albums = """
        [{"id":"album-1","album":"Test Album","artist":"Test Artist","year":2024,"genre":"Rock","track_count":10,"cover":null,"publisher":null,"country":null,"type":"Album","status":"Official","total_duration":2400.0,"original_date":null,"mb_id":null},{"id":"album-2","album":"Second Album","artist":"Another Artist","year":2023,"genre":"Jazz","track_count":8,"cover":null,"publisher":null,"country":null,"type":"Album","status":"Official","total_duration":1800.0,"original_date":null,"mb_id":null}]
        """

        let tracks = """
        [{"id":"track-1","title":"First Track","artist":"Test Artist","album_artist":"Test Artist","album":"Test Album","duration":240.0,"no":1,"url":"/api/stream/track-1","bit_rate":320,"year":2024,"cover":null},{"id":"track-2","title":"Second Track","artist":"Test Artist","album_artist":"Test Artist","album":"Test Album","duration":180.0,"no":2,"url":"/api/stream/track-2","bit_rate":320,"year":2024,"cover":null}]
        """

        mockResponses["/api/stats"] = (200, Data(stats.utf8))
        mockResponses["/api/cat/artist"] = (200, Data(categories.utf8))
        mockResponses["/api/cat/genre"] = (200, Data(categories.utf8))
        mockResponses["/api/cat/year"] = (200, Data(years.utf8))
        mockResponses["/api/cat/publisher"] = (200, Data(categories.utf8))
        mockResponses["/api/cat/country"] = (200, Data(categories.utf8))
        mockResponses["/api/cat/type"] = (200, Data(categories.utf8))
        mockResponses["/api/cat/status"] = (200, Data(categories.utf8))
        mockResponses["/api/cat/album"] = (200, Data(albums.utf8))
        mockResponses["/api/albums"] = (200, Data(albums.utf8))
        mockResponses["/api/album/"] = (200, Data(tracks.utf8))  // prefix match for album tracks
    }

    /// Register a custom mock for a specific path (used by tests via launch environment)
    static func setMock(path: String, statusCode: Int, data: Data) {
        mockResponses[path] = (statusCode, data)
    }

    /// Register a malformed response to test error handling
    static func setMalformedMock(path: String) {
        mockResponses[path] = (200, Data("not valid json{{{".utf8))
    }

    // MARK: - URLProtocol overrides

    override class func canInit(with request: URLRequest) -> Bool {
        guard let url = request.url else { return false }
        let path = url.path
        return mockResponses.keys.contains(where: { path.contains($0) })
    }

    override class func canonicalRequest(for request: URLRequest) -> URLRequest {
        request
    }

    override func startLoading() {
        guard let url = request.url else {
            client?.urlProtocol(self, didFailWithError: URLError(.badURL))
            return
        }

        let path = url.path
        var matchedResponse: (Int, Data)?

        // Try exact match first, then prefix match
        if let exact = MockURLProtocol.mockResponses[path] {
            matchedResponse = exact
        } else {
            for (key, value) in MockURLProtocol.mockResponses where path.contains(key) {
                matchedResponse = value
                break
            }
        }

        guard let (statusCode, data) = matchedResponse else {
            client?.urlProtocol(self, didFailWithError: URLError(.fileDoesNotExist))
            return
        }

        let response = HTTPURLResponse(
            url: url,
            statusCode: statusCode,
            httpVersion: "HTTP/1.1",
            headerFields: ["Content-Type": "application/json"]
        )!

        client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
        client?.urlProtocol(self, didLoad: data)
        client?.urlProtocolDidFinishLoading(self)
    }

    override func stopLoading() {}
}
