// Package dockerclient is the narrow Docker API surface consumed by
// `internal/runtime`. Its sole responsibility is to translate between the
// runtime domain and the Moby SDK; no orchestration, persistence, or
// notification logic lives in this package.
//
// The package is intentionally small. The implementation only surfaces the
// container-lifecycle calls the runtime module needs (`EnsureNetwork`,
// `PullImage`, `InspectImage`, `InspectContainer`, `Run`, `Stop`,
// `Remove`, `List`); any future functionality is introduced as an
// additive method on the `Client` interface so the runtime package can
// adopt it without round-tripping through Moby SDK type imports.
//
// Production wiring uses *Adapter, which delegates to
// `github.com/moby/moby/client`. Unit tests in `internal/runtime` and
// elsewhere should mock the `Client` interface directly rather than
// reaching into Moby types.
package dockerclient

import (
	"time"
)

// PullPolicy enumerates the supported image-pull behaviours documented in
// `backend/README.md` §4 under `BACKEND_RUNTIME_IMAGE_PULL_POLICY`.
type PullPolicy string

const (
	// PullPolicyIfMissing pulls the image only when it is absent from the
	// local Docker daemon.
	PullPolicyIfMissing PullPolicy = "if_missing"

	// PullPolicyAlways pulls the image on every Run.
	PullPolicyAlways PullPolicy = "always"

	// PullPolicyNever skips the pull and fails Run when the image is
	// absent locally.
	PullPolicyNever PullPolicy = "never"
)

// IsKnown reports whether p belongs to the closed PullPolicy vocabulary.
func (p PullPolicy) IsKnown() bool {
	switch p {
	case PullPolicyIfMissing, PullPolicyAlways, PullPolicyNever:
		return true
	default:
		return false
	}
}

// ManagedLabel is the Docker container label runtime stamps on every
// engine container so the reconciler and the events listener can
// identify Galaxy-managed containers from unrelated workloads sharing
// the daemon.
const ManagedLabel = "galaxy.backend"

// ManagedLabelValue is the string value paired with `ManagedLabel`.
const ManagedLabelValue = "1"

// RunSpec is the request shape used by Client.Run. Producers populate
// it inside `runtime.Service.StartGame`.
type RunSpec struct {
	// Name is the container name (typically `galaxy-game-{game_id}`).
	Name string

	// Image is the resolved image reference (e.g.
	// `galaxy-game:0.1.0`).
	Image string

	// Hostname is the container hostname; the engine endpoint URL
	// `http://galaxy-game-{game_id}:8080` resolves through Docker DNS
	// against this name on the user-defined network.
	Hostname string

	// Network is the user-defined Docker network name the container
	// attaches to.
	Network string

	// Env lists the environment variables forwarded to the container.
	Env map[string]string

	// Cmd overrides the entrypoint arguments. Production callers leave
	// it nil so the engine image's CMD runs.
	Cmd []string

	// Labels are applied at create time. The adapter merges
	// `ManagedLabel=ManagedLabelValue` into this map automatically;
	// callers may add more entries.
	Labels map[string]string

	// BindMounts describe the host-to-container bind mounts. Galaxy
	// uses exactly one in MVP (the per-game state directory).
	BindMounts []BindMount

	// LogDriver is the Docker log-driver name (e.g. `json-file`).
	LogDriver string

	// LogOpts is the comma-separated `key=value` list forwarded to the
	// log driver. May be empty.
	LogOpts string

	// CPUQuota is the `--cpus` value applied as a resource limit.
	CPUQuota float64

	// Memory is the `--memory` value (e.g. `512m`) applied as a
	// resource limit.
	Memory string

	// PIDsLimit is the `--pids-limit` value.
	PIDsLimit int

	// PullPolicy selects how Run resolves a missing image. Defaults to
	// PullPolicyIfMissing when zero.
	PullPolicy PullPolicy
}

// BindMount stores one host-to-container bind mount.
type BindMount struct {
	// HostPath is the absolute host path bound into the container.
	HostPath string

	// MountPath is the absolute in-container path the host directory
	// is mounted at.
	MountPath string

	// ReadOnly mounts the host path read-only when true.
	ReadOnly bool
}

// RunResult is the response shape returned by Client.Run.
type RunResult struct {
	// ContainerID identifies the created container.
	ContainerID string

	// EngineEndpoint is the URL Galaxy uses to reach the engine. The
	// adapter synthesises it as `http://{Hostname}:8080`.
	EngineEndpoint string

	// StartedAt is the wall-clock observed by the daemon for the start
	// event.
	StartedAt time.Time
}

// ImageInspect carries the subset of `docker image inspect` fields the
// runtime reads.
type ImageInspect struct {
	// Ref is the image reference the inspection was scoped to.
	Ref string

	// Labels are the image-level labels (e.g. `com.galaxy.cpu_quota`).
	Labels map[string]string
}

// ContainerInspect carries the subset of `docker inspect` fields the
// runtime reads from a running or exited container.
type ContainerInspect struct {
	// ID identifies the container.
	ID string

	// Name is the container name (without leading `/`).
	Name string

	// ImageRef is the image reference the container was started from.
	ImageRef string

	// Hostname is the container hostname.
	Hostname string

	// Labels are the container labels assigned at create time.
	Labels map[string]string

	// Status is the verbatim Docker `State.Status` value (e.g.
	// `running`, `exited`).
	Status string

	// Health is the verbatim Docker `State.Health.Status` value
	// (e.g. `healthy`, `unhealthy`). Empty when the image declares no
	// HEALTHCHECK.
	Health string

	// StartedAt is the daemon-observed start wall-clock.
	StartedAt time.Time

	// FinishedAt is the daemon-observed exit wall-clock. Zero when the
	// container is still running.
	FinishedAt time.Time

	// ExitCode is the exit code reported by the daemon. Zero when the
	// container is still running.
	ExitCode int
}

// ContainerSummary carries the subset of `docker ps` fields the runtime
// reads.
type ContainerSummary struct {
	// ID identifies the container.
	ID string

	// Name is the container name (without leading `/`).
	Name string

	// ImageRef is the image reference.
	ImageRef string

	// Hostname is the container hostname.
	Hostname string

	// Labels are the container labels assigned at create time.
	Labels map[string]string

	// Status is the verbatim Docker `State.Status` value.
	Status string

	// StartedAt is the daemon-observed start wall-clock.
	StartedAt time.Time
}

// ListFilter narrows the ContainerList result. Empty fields match
// everything.
type ListFilter struct {
	// Labels lists `key=value` label pairs that must all be present on
	// the container. Empty matches every container.
	Labels map[string]string
}
