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

import Testing
import Foundation
@testable import Confab

@Suite("ExternalMCPServer Codable")
struct ExternalMCPServerCodableTests {

    private static func makeCoders() -> (JSONEncoder, JSONDecoder) {
        let encoder = JSONEncoder()
        encoder.dateEncodingStrategy = .iso8601
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        return (encoder, decoder)
    }

    @Test("Decodes old-shape JSON (saved before env/HTTP fields existed) with safe defaults")
    func decodesOldShapeJSON() throws {
        // Exactly the 7 keys ExternalMCPServer had before transportKind/env/url/bearerToken/headers
        // were added — this is what's actually sitting in existing users' settings DB right now.
        let oldJSON = """
        {
            "id": "00000000-0000-0000-0000-000000000001",
            "name": "Safari",
            "command": "safaridriver",
            "args": ["--mcp"],
            "isEnabled": true,
            "timeout": 30,
            "createdAt": "2026-01-01T00:00:00Z"
        }
        """
        let (_, decoder) = Self.makeCoders()
        let server = try decoder.decode(ExternalMCPServer.self, from: Data(oldJSON.utf8))

        #expect(server.name == "Safari")
        #expect(server.command == "safaridriver")
        #expect(server.args == ["--mcp"])
        #expect(server.transportKind == .stdio)
        #expect(server.env.isEmpty)
        #expect(server.url.isEmpty)
        #expect(server.bearerToken.isEmpty)
        #expect(server.headers.isEmpty)
    }

    @Test("An array of old-shape servers (the real settings-JSON shape) decodes without dropping any")
    func decodesOldShapeArray() throws {
        let oldJSON = """
        [
            {"id": "00000000-0000-0000-0000-000000000001", "name": "Safari", "command": "safaridriver",
             "args": ["--mcp"], "isEnabled": true, "timeout": 30, "createdAt": "2026-01-01T00:00:00Z"},
            {"id": "00000000-0000-0000-0000-000000000002", "name": "Other", "command": "some-tool",
             "args": [], "isEnabled": false, "timeout": 15, "createdAt": "2026-02-01T00:00:00Z"}
        ]
        """
        let (_, decoder) = Self.makeCoders()
        let servers = try decoder.decode([ExternalMCPServer].self, from: Data(oldJSON.utf8))
        #expect(servers.count == 2)
    }

    @Test("Round-trips a full HTTP-transport server through encode/decode")
    func roundTripsHTTPServer() throws {
        let original = ExternalMCPServer(
            name: "Obsidian",
            transportKind: .http,
            url: "http://127.0.0.1:27123/mcp/",
            bearerToken: "secret-token",
            headers: ["X-Extra": "value"],
            timeout: 45
        )
        let (encoder, decoder) = Self.makeCoders()
        let data = try encoder.encode(original)
        let decoded = try decoder.decode(ExternalMCPServer.self, from: data)

        #expect(decoded.id == original.id)
        #expect(decoded.transportKind == .http)
        #expect(decoded.url == "http://127.0.0.1:27123/mcp/")
        #expect(decoded.bearerToken == "secret-token")
        #expect(decoded.headers == ["X-Extra": "value"])
    }

    @Test("Round-trips a stdio-transport server with env vars")
    func roundTripsStdioServerWithEnv() throws {
        let original = ExternalMCPServer(
            name: "Custom",
            command: "npx",
            args: ["-y", "some-tool"],
            env: ["API_KEY": "abc123"],
            timeout: 30
        )
        let (encoder, decoder) = Self.makeCoders()
        let data = try encoder.encode(original)
        let decoded = try decoder.decode(ExternalMCPServer.self, from: data)

        #expect(decoded.transportKind == .stdio)
        #expect(decoded.env == ["API_KEY": "abc123"])
        #expect(decoded.command == "npx")
        #expect(decoded.args == ["-y", "some-tool"])
    }
}
