//
//  OpenRouterProviderTests.swift
//  oAITests
//
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
// Copyright (C) 2026 Rune Olsen

import Testing
import Foundation
@testable import Confab

@Suite("OpenRouterProvider request/response conversion")
struct OpenRouterProviderTests {

    private var provider: OpenRouterProvider { OpenRouterProvider(apiKey: "test-key") }

    // MARK: - buildAPIRequest

    @Test("Plain text message with no attachments uses simple string content")
    func buildRequestPlainText() throws {
        let request = ChatRequest(messages: [Message(role: .user, content: "hello")], model: "openai/gpt-4o")
        let apiRequest = try provider.buildAPIRequest(from: request)
        guard case .string(let text) = apiRequest.messages.first?.content else {
            Issue.record("Expected .string content for a message with no attachments")
            return
        }
        #expect(text == "hello")
    }

    @Test("Message with an image attachment uses array content with a base64 data URL")
    func buildRequestWithImageAttachment() throws {
        let attachment = FileAttachment(path: "photo.png", type: .image, data: Data([0x01, 0x02]))
        let message = Message(role: .user, content: "check this out", attachments: [attachment])
        let request = ChatRequest(messages: [message], model: "openai/gpt-4o")
        let apiRequest = try provider.buildAPIRequest(from: request)
        guard case .array(let items) = apiRequest.messages.first?.content else {
            Issue.record("Expected .array content for a message with attachments")
            return
        }
        #expect(items.count == 2) // text + image
    }

    @Test("Online mode appends :online suffix, but not for image generation requests")
    func onlineModeSuffix() throws {
        let base = ChatRequest(messages: [Message(role: .user, content: "hi")], model: "openai/gpt-4o", onlineMode: true)
        let request = try provider.buildAPIRequest(from: base)
        #expect(request.model == "openai/gpt-4o:online")

        let imageGenRequest = ChatRequest(messages: [Message(role: .user, content: "hi")], model: "openai/gpt-4o", onlineMode: true, imageGeneration: true)
        let noSuffix = try provider.buildAPIRequest(from: imageGenRequest)
        #expect(noSuffix.model == "openai/gpt-4o")
    }

    @Test("Online mode does not double-append :online if the model already has it")
    func onlineModeNoDoubleSuffix() throws {
        let request = ChatRequest(messages: [Message(role: .user, content: "hi")], model: "openai/gpt-4o:online", onlineMode: true)
        let apiRequest = try provider.buildAPIRequest(from: request)
        #expect(apiRequest.model == "openai/gpt-4o:online")
    }

    @Test("Anthropic models get an explicit cache_control opt-in; others don't")
    func cacheControlOnlyForAnthropic() throws {
        let anthropicRequest = ChatRequest(messages: [Message(role: .user, content: "hi")], model: "anthropic/claude-sonnet-4-5")
        let anthropicAPI = try provider.buildAPIRequest(from: anthropicRequest)
        #expect(anthropicAPI.cacheControl?.type == "ephemeral")

        let openAIRequest = ChatRequest(messages: [Message(role: .user, content: "hi")], model: "openai/gpt-4o")
        let openAIAPI = try provider.buildAPIRequest(from: openAIRequest)
        #expect(openAIAPI.cacheControl == nil)
    }

    // MARK: - convertToChatResponse

    @Test("Throws invalidResponse when there are no choices")
    func convertToChatResponseThrowsOnEmptyChoices() {
        let apiResponse = OpenRouterChatResponse(id: "x", model: "m", choices: [], usage: nil, created: 0)
        #expect(throws: (any Error).self) {
            try provider.convertToChatResponse(apiResponse)
        }
    }

    // MARK: - decodeImageOutputs

    @Test("Decodes a base64 data URL into raw Data")
    func decodeImageOutputsValidDataURL() {
        let payload = Data([0xDE, 0xAD, 0xBE, 0xEF])
        let dataURL = "data:image/png;base64,\(payload.base64EncodedString())"
        let output = OpenRouterChatResponse.ImageOutput(imageUrl: .init(url: dataURL))
        let decoded = provider.decodeImageOutputs([output])
        #expect(decoded?.first == payload)
    }

    @Test("Returns nil for an empty outputs array")
    func decodeImageOutputsEmpty() {
        #expect(provider.decodeImageOutputs([]) == nil)
    }

    @Test("Skips a malformed URL with no comma separator")
    func decodeImageOutputsMalformedURL() {
        let output = OpenRouterChatResponse.ImageOutput(imageUrl: .init(url: "not-a-data-url"))
        #expect(provider.decodeImageOutputs([output]) == nil)
    }
}
