import std/[unittest, times, json, options, strutils]
import ../src/nip/metadata

suite "Package Metadata Generation":

  test "generateMetadata creates complete metadata for NPK":
    # Requirement 7.1: source origin, maintainer, upstream URL, build timestamp
    let source = SourceInfo(
      origin: "https://github.com/example/package",
      maintainer: "John Doe <john@example.com>",
      upstreamUrl: "https://example.com/package",
      sourceHash: "xxh3-abc123"
    )

    # Requirement 7.2: compiler version, flags, target architecture, build hash
    let buildInfo = BuildInfo(
      compilerVersion: "gcc-13.2.0",
      compilerFlags: @["-O2", "-march=native"],
      targetArchitecture: "x86_64",
      buildHash: "xxh3-def456",
      buildTimestamp: now()
    )

    let metadata = generateMetadata(
      packageName = "nginx",
      version = "1.24.0",
      formatType = FormatType.NPK,
      source = source,
      buildInfo = buildInfo
    )

    check metadata.packageName == "nginx"
    check metadata.version == "1.24.0"
    check metadata.formatType == FormatType.NPK
    check metadata.source.origin == "https://github.com/example/package"
    check metadata.source.maintainer == "John Doe <john@example.com>"
    check metadata.buildInfo.compilerVersion == "gcc-13.2.0"
    check metadata.buildInfo.buildHash == "xxh3-def456"

  test "generateMetadata creates complete metadata for NIP":
    let source = SourceInfo(
      origin: "https://flathub.org/apps/firefox",
      maintainer: "Mozilla Foundation",
      upstreamUrl: "https://www.mozilla.org/firefox/",
      sourceHash: "xxh3-xyz789"
    )

    let buildInfo = BuildInfo(
      compilerVersion: "clang-16.0.0",
      compilerFlags: @["-O3", "-flto"],
      targetArchitecture: "x86_64",
      buildHash: "xxh3-ghi012",
      buildTimestamp: now()
    )

    let metadata = generateMetadata(
      packageName = "firefox",
      version = "120.0",
      formatType = FormatType.NIP,
      source = source,
      buildInfo = buildInfo
    )

    check metadata.formatType == FormatType.NIP
    check metadata.source.upstreamUrl == "https://www.mozilla.org/firefox/"

  test "generateMetadata creates complete metadata for NEXTER":
    let source = SourceInfo(
      origin: "https://hub.docker.com/_/nginx",
      maintainer: "NGINX Team",
      upstreamUrl: "https://nginx.org/",
      sourceHash: "xxh3-jkl345"
    )

    let buildInfo = BuildInfo(
      compilerVersion: "gcc-12.3.0",
      compilerFlags: @["-O2"],
      targetArchitecture: "aarch64",
      buildHash: "xxh3-mno678",
      buildTimestamp: now()
    )

    let metadata = generateMetadata(
      packageName = "nginx-container",
      version = "1.24.0",
      formatType = FormatType.NEXTER,
      source = source,
      buildInfo = buildInfo
    )

    check metadata.formatType == FormatType.NEXTER
    check metadata.buildInfo.targetArchitecture == "aarch64"

  test "metadata includes provenance chain":
    # Requirement 7.3: complete chain from source to installation
    let source = SourceInfo(
      origin: "https://github.com/example/package",
      maintainer: "John Doe <john@example.com>",
      upstreamUrl: "https://example.com/package",
      sourceHash: "xxh3-abc123"
    )

    let buildInfo = BuildInfo(
      compilerVersion: "gcc-13.2.0",
      compilerFlags: @["-O2"],
      targetArchitecture: "x86_64",
      buildHash: "xxh3-def456",
      buildTimestamp: now()
    )

    let provenance = ProvenanceChain(
      sourceDownload: ProvenanceStep(
        timestamp: now(),
        action: "source_download",
        hash: "xxh3-abc123",
        verifiedBy: "nip-0.2.0"
      ),
      build: ProvenanceStep(
        timestamp: now(),
        action: "build",
        hash: "xxh3-def456",
        verifiedBy: "nip-0.2.0"
      ),
      installation: ProvenanceStep(
        timestamp: now(),
        action: "installation",
        hash: "xxh3-ghi789",
        verifiedBy: "nip-0.2.0"
      )
    )

    let metadata = generateMetadata(
      packageName = "test-package",
      version = "1.0.0",
      formatType = FormatType.NPK,
      source = source,
      buildInfo = buildInfo,
      provenance = some(provenance)
    )

    check metadata.provenance.isSome
    check metadata.provenance.get().sourceDownload.action == "source_download"
    check metadata.provenance.get().build.action == "build"
    check metadata.provenance.get().installation.action == "installation"

  test "metadata can be serialized to JSON":
    # Requirement 7.4: metadata can be queried
    let source = SourceInfo(
      origin: "https://github.com/example/package",
      maintainer: "John Doe <john@example.com>",
      upstreamUrl: "https://example.com/package",
      sourceHash: "xxh3-abc123"
    )

    let buildInfo = BuildInfo(
      compilerVersion: "gcc-13.2.0",
      compilerFlags: @["-O2", "-march=native"],
      targetArchitecture: "x86_64",
      buildHash: "xxh3-def456",
      buildTimestamp: now()
    )

    let metadata = generateMetadata(
      packageName = "nginx",
      version = "1.24.0",
      formatType = FormatType.NPK,
      source = source,
      buildInfo = buildInfo
    )

    let jsonStr = toJson(metadata)
    check jsonStr.len > 0

    # Verify JSON contains required fields
    let parsed = parseJson(jsonStr)
    check parsed.hasKey("packageName")
    check parsed.hasKey("version")
    check parsed.hasKey("formatType")
    check parsed.hasKey("source")
    check parsed.hasKey("buildInfo")
    check parsed["source"].hasKey("origin")
    check parsed["source"].hasKey("maintainer")
    check parsed["source"].hasKey("upstreamUrl")
    check parsed["buildInfo"].hasKey("compilerVersion")
    check parsed["buildInfo"].hasKey("buildHash")

  test "metadata can be deserialized from JSON":
    let jsonStr = """
    {
      "packageName": "nginx",
      "version": "1.24.0",
      "formatType": "NPK",
      "source": {
        "origin": "https://github.com/example/package",
        "maintainer": "John Doe <john@example.com>",
        "upstreamUrl": "https://example.com/package",
        "sourceHash": "xxh3-abc123"
      },
      "buildInfo": {
        "compilerVersion": "gcc-13.2.0",
        "compilerFlags": ["-O2", "-march=native"],
        "targetArchitecture": "x86_64",
        "buildHash": "xxh3-def456",
        "buildTimestamp": "2025-11-20T10:30:00Z"
      },
      "dependencies": [],
      "createdAt": "2025-11-20T10:30:00Z"
    }
    """

    let metadata = fromJson(jsonStr)
    check metadata.packageName == "nginx"
    check metadata.version == "1.24.0"
    check metadata.formatType == FormatType.NPK
    check metadata.source.origin == "https://github.com/example/package"
    check metadata.buildInfo.compilerVersion == "gcc-13.2.0"

  test "metadata uses xxh3 for build hashes":
    # Requirement 7.5: use xxh3 for build hashes
    let source = SourceInfo(
      origin: "https://github.com/example/package",
      maintainer: "John Doe <john@example.com>",
      upstreamUrl: "https://example.com/package",
      sourceHash: "xxh3-abc123"
    )

    let buildInfo = BuildInfo(
      compilerVersion: "gcc-13.2.0",
      compilerFlags: @["-O2"],
      targetArchitecture: "x86_64",
      buildHash: "xxh3-def456",  # Must use xxh3 prefix
      buildTimestamp: now()
    )

    let metadata = generateMetadata(
      packageName = "test-package",
      version = "1.0.0",
      formatType = FormatType.NPK,
      source = source,
      buildInfo = buildInfo
    )

    check metadata.buildInfo.buildHash.startsWith("xxh3-")
    check metadata.source.sourceHash.startsWith("xxh3-")

  test "metadata includes dependencies with build hashes":
    let source = SourceInfo(
      origin: "https://github.com/example/package",
      maintainer: "John Doe <john@example.com>",
      upstreamUrl: "https://example.com/package",
      sourceHash: "xxh3-abc123"
    )

    let buildInfo = BuildInfo(
      compilerVersion: "gcc-13.2.0",
      compilerFlags: @["-O2"],
      targetArchitecture: "x86_64",
      buildHash: "xxh3-def456",
      buildTimestamp: now()
    )

    let dependencies = @[
      DependencyInfo(
        name: "openssl",
        version: "3.0.0",
        buildHash: "xxh3-dep001"
      ),
      DependencyInfo(
        name: "zlib",
        version: "1.2.13",
        buildHash: "xxh3-dep002"
      )
    ]

    let metadata = generateMetadata(
      packageName = "nginx",
      version = "1.24.0",
      formatType = FormatType.NPK,
      source = source,
      buildInfo = buildInfo,
      dependencies = dependencies
    )

    check metadata.dependencies.len == 2
    check metadata.dependencies[0].name == "openssl"
    check metadata.dependencies[0].buildHash == "xxh3-dep001"
    check metadata.dependencies[1].name == "zlib"
    check metadata.dependencies[1].buildHash == "xxh3-dep002"
