//===----------------------------------------------------------------------===//
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//

import AsyncHTTPClient
import ContainerResource
import Foundation

// MARK: - Network inspect output

public struct NetworkInspectOutput: Codable {
    public struct Status: Codable {
        public let ipv4Subnet: String?
        public let ipv4Gateway: String?
        public let ipv6Subnet: String?
    }
    public let id: String
    public let configuration: NetworkConfiguration
    public let status: Status
}

// MARK: - Network lifecycle helpers

extension ContainerFixture {

    /// Creates a named network, throwing on failure.
    public func doNetworkCreate(_ name: String, args: [String] = []) throws {
        var arguments = ["network", "create"]
        arguments += args
        arguments.append(name)
        try run(arguments).check()
    }

    /// Deletes a named network, throwing on failure.
    public func doNetworkDelete(_ name: String) throws {
        try run(["network", "delete", name]).check()
    }

    /// Deletes a named network, silently ignoring errors.
    public func doNetworkDeleteIfExists(_ name: String) {
        _ = try? run(["network", "delete", name])
    }

    /// Inspects a network and returns decoded output.
    public func inspectNetwork(_ name: String) throws -> NetworkInspectOutput {
        let result = try run(["network", "inspect", name]).check()
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        let networks = try decoder.decode([NetworkInspectOutput].self, from: result.outputData)
        guard let network = networks.first else {
            throw CommandError.executionFailed("network inspect returned empty array")
        }
        return network
    }

    /// Returns an `HTTPClient` for use in network connectivity tests.
    public func makeHTTPClient() -> HTTPClient {
        HTTPClient(eventLoopGroupProvider: .singleton)
    }

    /// Polls `url` via HTTP GET until it returns a 2xx status.
    ///
    /// Useful after a container reaches `running` state, since that only proves
    /// the container's init process is up — a server inside may still be starting.
    public func waitForHTTPOk(
        _ url: String, using client: HTTPClient, attempts: Int = 10, delay: Duration = .seconds(1)
    ) async throws {
        try await retry(attempts: attempts, delay: delay) {
            do {
                var req = HTTPClientRequest(url: url)
                req.method = .GET
                let resp = try await client.execute(req, timeout: .seconds(3))
                return resp.status.code >= 200 && resp.status.code < 300
            } catch {
                return false
            }
        }
    }
}
