## Test suite for UTCP Protocol implementation

import unittest
import std/[tables, json, options]
import ../src/nimpak/utcp_protocol

suite "UTCP Address Assignment":
  test "Assign UTCP address to Nippel":
    let res = assignUTCPAddress(Nippel, "dev-env", "localhost")

    check res.isOk
    if res.isOk:
      let address = res.okValue
      check address.scheme == UtcpPlain
      check address.host == "localhost"
      check address.resourceType == Nippel
      check address.resourceName == "dev-env"

  test "Assign UTCP address with default host":
    let res = assignUTCPAddress(Nexter, "web-server")

    check res.isOk
    let address = res.okValue
    check address.host.len > 0  # Should use hostname
    check address.resourceType == Nexter
    check address.resourceName == "web-server"

  test "Create agent endpoint":
    let res = createAgentEndpoint("n8n-workflow", "localhost")

    check res.isOk
    let address = res.okValue
    check address.resourceType == Agent
    check address.resourceName == "n8n-workflow"

  test "Create tool endpoint":
    let res = createToolEndpoint("nexus", "localhost")

    check res.isOk
    let address = res.okValue
    check address.resourceType == Tool
    check address.resourceName == "nexus"

  test "Create LLM endpoint":
    let res = createLLMEndpoint("llama2", "localhost")

    check res.isOk
    let address = res.okValue
    check address.resourceType == LLM
    check address.resourceName == "llama2"


suite "UTCP Address Parsing":
  test "Parse simple UTCP address":
    let res = parseUTCPAddress("utcp://localhost/nippel/dev-env")

    check res.isOk
    let address = res.okValue
    check address.scheme == UtcpPlain
    check address.host == "localhost"
    check address.resourceType == Nippel
    check address.resourceName == "dev-env"

  test "Parse UTCP address with port":
    let res = parseUTCPAddress("utcp://localhost:8080/nexter/web-server")

    check res.isOk
    let address = res.okValue
    check address.port.isSome
    check address.port.get() == 8080

  test "Parse UTCP address with path":
    let res = parseUTCPAddress("utcp://localhost/nippel/dev-env/state")

    check res.isOk
    let address = res.okValue
    check address.path == "/state"

  test "Parse UTCP address with query":
    let res = parseUTCPAddress("utcp://localhost/nippel/dev-env?cmd=vim")

    check res.isOk
    let address = res.okValue
    check address.query.hasKey("cmd")
    check address.query["cmd"] == "vim"

  test "Parse secure UTCP address":
    let res = parseUTCPAddress("utcps://localhost/agent/n8n")

    check res.isOk
    let address = res.okValue
    check address.scheme == UtcpSecure

  test "Parse invalid scheme":
    let res = parseUTCPAddress("http://localhost/nippel/dev-env")

    check not res.isOk

  test "Parse invalid path":
    let res = parseUTCPAddress("utcp://localhost/invalid")

    check not res.isOk


suite "UTCP Address Formatting":
  test "Format simple address":
    let address = newUTCPAddress("localhost", Nippel, "dev-env")
    let formatted = formatUTCPAddress(address)

    check formatted == "utcp://localhost/nippel/dev-env"

  test "Format address with port":
    let address = newUTCPAddress("localhost", Nexter, "web-server", port = some(8080))
    let formatted = formatUTCPAddress(address)

    check formatted == "utcp://localhost:8080/nexter/web-server"

  test "Format address with path":
    let address = newUTCPAddress("localhost", Nippel, "dev-env", path = "/state")
    let formatted = formatUTCPAddress(address)

    check formatted == "utcp://localhost/nippel/dev-env/state"

  test "Format address with query":
    var query = initTable[string, string]()
    query["cmd"] = "vim"
    let address = newUTCPAddress("localhost", Nippel, "dev-env", query = query)
    let formatted = formatUTCPAddress(address)

    check formatted.contains("?cmd=vim")

  test "Format secure address":
    let address = newUTCPAddress("localhost", Agent, "n8n", scheme = UtcpSecure)
    let formatted = formatUTCPAddress(address)

    check formatted.startsWith("utcps://")

suite "UTCP Request Creation":
  test "Create GET request":
    let address = newUTCPAddress("localhost", Nippel, "dev-env")
    let request = newUTCPRequest(address, GET)

    check request.meth == GET
    check request.address.resourceName == "dev-env"
    check request.headers.hasKey("User-Agent")
    check request.headers.hasKey("UTCP-Version")

  test "Create POST request with payload":
    let address = newUTCPAddress("localhost", Nippel, "dev-env")
    let payload = %*{"command": "vim"}
    let request = newUTCPRequest(address, POST, payload)

    check request.meth == POST
    check request.payload.hasKey("command")
    check request.payload["command"].getStr() == "vim"


suite "UTCP Response Creation":
  test "Create success response":
    let response = newUTCPResponse(Ok, %*{"status": "active"}, "req-123")

    check response.status == Ok
    check response.requestId == "req-123"
    check response.data.hasKey("status")

  test "Create error response":
    let response = newUTCPResponse(NotFound, %*{"error": "Not found"})

    check response.status == NotFound
    check response.data.hasKey("error")

suite "UTCP Method Handlers":
  test "Handle GET state":
    let res = handleGetState(Nippel, "dev-env")

    check res.isOk
    let state = res.okValue
    check state.hasKey("resourceType")
    check state.hasKey("resourceName")
    check state.hasKey("status")

  test "Handle activate":
    let res = handleActivate(Nippel, "dev-env")

    check res.isOk
    let response = res.okValue
    check response.hasKey("action")
    check response["action"].getStr() == "activate"

  test "Handle deactivate":
    let res = handleDeactivate(Nippel, "dev-env")

    check res.isOk
    let response = res.okValue
    check response.hasKey("action")
    check response["action"].getStr() == "deactivate"

  test "Handle get merkle":
    let res = handleGetMerkle(Nippel, "dev-env")

    check res.isOk
    let merkle = res.okValue
    check merkle.hasKey("merkleRoot")

  test "Handle exec":
    let res = handleExec(Nippel, "dev-env", "vim")

    check res.isOk
    let execResult = res.okValue
    check execResult.hasKey("command")
    check execResult["command"].getStr() == "vim"


suite "UTCP Request Routing":
  test "Route GET state request":
    let address = newUTCPAddress("localhost", Nippel, "dev-env", path = "/state")
    let request = newUTCPRequest(address, GET)
    let res = routeUTCPRequest(request)

    check res.isOk
    let response = res.okValue
    check response.status == Ok
    check response.data.hasKey("resourceType")

  test "Route POST activate request":
    let address = newUTCPAddress("localhost", Nippel, "dev-env", path = "/activate")
    let request = newUTCPRequest(address, POST)
    let res = routeUTCPRequest(request)

    check res.isOk
    let response = res.okValue
    check response.status == Ok
    check response.data["action"].getStr() == "activate"

  test "Route POST deactivate request":
    let address = newUTCPAddress("localhost", Nippel, "dev-env", path = "/deactivate")
    let request = newUTCPRequest(address, POST)
    let res = routeUTCPRequest(request)

    check res.isOk
    let response = res.okValue
    check response.status == Ok
    check response.data["action"].getStr() == "deactivate"

  test "Route GET merkle request":
    let address = newUTCPAddress("localhost", Nippel, "dev-env", path = "/merkle")
    let request = newUTCPRequest(address, GET)
    let res = routeUTCPRequest(request)

    check res.isOk
    let response = res.okValue
    check response.status == Ok
    check response.data.hasKey("merkleRoot")

  test "Route POST exec request":
    let address = newUTCPAddress("localhost", Nippel, "dev-env", path = "/exec")
    let payload = %*{"command": "vim"}
    let request = newUTCPRequest(address, POST, payload)
    let res = routeUTCPRequest(request)

    check res.isOk
    let response = res.okValue
    check response.status == Ok
    check response.data["command"].getStr() == "vim"

  test "Route invalid path":
    let address = newUTCPAddress("localhost", Nippel, "dev-env", path = "/invalid")
    let request = newUTCPRequest(address, GET)
    let res = routeUTCPRequest(request)

    check res.isOk
    let response = res.okValue
    check response.status == NotFound

  test "Route unsupported method":
    let address = newUTCPAddress("localhost", Nippel, "dev-env")
    let request = newUTCPRequest(address, DELETE)
    let res = routeUTCPRequest(request)

    check res.isOk
    let response = res.okValue
    check response.status == MethodNotAllowed


suite "UTCP Utility Functions":
  test "Check local address - localhost":
    let address = newUTCPAddress("localhost", Nippel, "dev-env")
    check isLocalAddress(address)

  test "Check local address - 127.0.0.1":
    let address = newUTCPAddress("127.0.0.1", Nippel, "dev-env")
    check isLocalAddress(address)

  test "Check remote address":
    let address = newUTCPAddress("remote.example.com", Nippel, "dev-env")
    check not isLocalAddress(address)

  test "Get default port for plain UTCP":
    let port = getDefaultPort(UtcpPlain)
    check port == UTCP_DEFAULT_PORT

  test "Get default port for secure UTCP":
    let port = getDefaultPort(UtcpSecure)
    check port == UTCP_DEFAULT_PORT + 1

  test "Validate valid address":
    let address = newUTCPAddress("localhost", Nippel, "dev-env")
    let res = validateAddress(address)
    check res.isOk

  test "Validate address with empty host":
    let address = UTCPAddress(
      scheme: UtcpPlain,
      host: "",
      resourceType: Nippel,
      resourceName: "dev-env"
    )
    let res = validateAddress(address)
    check not res.isOk

  test "Validate address with empty resource name":
    let address = UTCPAddress(
      scheme: UtcpPlain,
      host: "localhost",
      resourceType: Nippel,
      resourceName: ""
    )
    let res = validateAddress(address)
    check not res.isOk

suite "UTCP Resource Types":
  test "Create Nippel address":
    let address = newUTCPAddress("localhost", Nippel, "dev-env")
    check address.resourceType == Nippel

  test "Create Nexter address":
    let address = newUTCPAddress("localhost", Nexter, "web-server")
    check address.resourceType == Nexter

  test "Create Package address":
    let address = newUTCPAddress("localhost", Package, "nginx")
    check address.resourceType == Package

  test "Create System address":
    let address = newUTCPAddress("localhost", System, "config")
    check address.resourceType == System

  test "Create Tool address":
    let address = newUTCPAddress("localhost", Tool, "nexus")
    check address.resourceType == Tool

  test "Create Agent address":
    let address = newUTCPAddress("localhost", Agent, "n8n-workflow")
    check address.resourceType == Agent

  test "Create LLM address":
    let address = newUTCPAddress("localhost", LLM, "llama2")
    check address.resourceType == LLM
