package real

import (
	"archive/tar"
	"compress/gzip"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/ocdp/cluster-service/internal/domain/entity"
	"github.com/ocdp/cluster-service/internal/domain/repository"
	"github.com/opencontainers/go-digest"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"oras.land/oras-go/v2/registry/remote"
	"oras.land/oras-go/v2/registry/remote/auth"
)

// OCIClient 真实的 OCI 客户端实现（使用 ORAS）
type OCIClient struct {
	httpClient *http.Client
}

type harborProject struct {
	Name string `json:"name"`
}

type harborRepository struct {
	Name          string `json:"name"`
	ArtifactCount int    `json:"artifact_count"`
}

type harborTag struct {
	Name     string `json:"name"`
	PushTime string `json:"push_time"`
}

type harborArtifact struct {
	Digest       string            `json:"digest"`
	MediaType    string            `json:"media_type"`
	ArtifactType string            `json:"artifact_type"`
	Size         int64             `json:"size"`
	PushTime     string            `json:"push_time"`
	Tags         []harborTag       `json:"tags"`
	Annotations  map[string]string `json:"annotations"`
}

// NewOCIClient 创建真实的 OCI 客户端
func NewOCIClient() repository.OCIClient {
	return &OCIClient{
		httpClient: &http.Client{},
	}
}

// getRegistry 创建 ORAS Registry 客户端
func (c *OCIClient) getRegistry(reg *entity.Registry) (*remote.Registry, error) {
	// 解析 Registry URL
	registryURL := strings.TrimPrefix(reg.URL, "https://")
	registryURL = strings.TrimPrefix(registryURL, "http://")

	registry, err := remote.NewRegistry(registryURL)
	if err != nil {
		return nil, fmt.Errorf("failed to create registry client: %w", err)
	}

	// 设置认证
	if reg.Username != "" && reg.Password != "" {
		registry.Client = &auth.Client{
			Client: c.httpClient,
			Credential: auth.StaticCredential(registryURL, auth.Credential{
				Username: reg.Username,
				Password: reg.Password,
			}),
		}
	}

	// 设置 PlainHTTP（如果是 insecure）
	registry.PlainHTTP = reg.Insecure

	return registry, nil
}

// ListRepositories 列出 Registry 中的 repositories.
// Harbor registry 优先使用 Harbor v2.0 API，避免 robot 账号依赖 /v2/_catalog 全局权限。
func (c *OCIClient) ListRepositories(ctx context.Context, registry *entity.Registry, artifactType string) ([]string, error) {
	repositories, harborErr := c.listHarborRepositories(ctx, registry, artifactType)
	if harborErr == nil {
		return repositories, nil
	}

	repositories, catalogErr := c.listOCIRepositories(ctx, registry)
	if catalogErr != nil {
		return nil, fmt.Errorf("failed to list repositories via Harbor API: %v; OCI catalog fallback also failed: %w", harborErr, catalogErr)
	}

	if strings.EqualFold(strings.TrimSpace(artifactType), "chart") {
		chartRepos := make([]string, 0)
		for _, repo := range repositories {
			artifacts, err := c.ListArtifacts(ctx, registry, repo, "chart")
			if err == nil && len(artifacts) > 0 {
				chartRepos = append(chartRepos, repo)
			}
		}
		return chartRepos, nil
	}

	return repositories, nil
}

func (c *OCIClient) listOCIRepositories(ctx context.Context, registry *entity.Registry) ([]string, error) {
	reg, err := c.getRegistry(registry)
	if err != nil {
		return nil, err
	}

	repositories := make([]string, 0)

	err = reg.Repositories(ctx, "", func(repos []string) error {
		repositories = append(repositories, repos...)
		return nil
	})

	if err != nil {
		return nil, fmt.Errorf("failed to list repositories: %w", err)
	}

	return repositories, nil
}

func (c *OCIClient) listHarborRepositories(ctx context.Context, registry *entity.Registry, artifactType string) ([]string, error) {
	projects, err := c.harborListProjects(ctx, registry)
	if err != nil {
		return nil, err
	}

	repositorySet := make(map[string]struct{})
	chartOnly := strings.EqualFold(strings.TrimSpace(artifactType), "chart") || strings.TrimSpace(artifactType) == ""

	for _, project := range projects {
		projectName := strings.TrimSpace(project.Name)
		if projectName == "" {
			continue
		}

		repositories, err := c.harborListProjectRepositories(ctx, registry, projectName)
		if err != nil {
			return nil, err
		}

		for _, harborRepo := range repositories {
			repoName := normalizeHarborRepositoryName(projectName, harborRepo.Name)
			if repoName == "" {
				continue
			}
			if chartOnly {
				artifacts, err := c.listHarborArtifacts(ctx, registry, repoName, "chart")
				if err != nil || len(artifacts) == 0 {
					continue
				}
			}
			repositorySet[repoName] = struct{}{}
		}
	}

	repositories := make([]string, 0, len(repositorySet))
	for repo := range repositorySet {
		repositories = append(repositories, repo)
	}
	sort.Strings(repositories)
	return repositories, nil
}

func (c *OCIClient) harborListProjects(ctx context.Context, registry *entity.Registry) ([]harborProject, error) {
	var projects []harborProject
	if err := c.harborGetPaged(ctx, registry, "/api/v2.0/projects", url.Values{"member": []string{"true"}}, &projects); err != nil {
		return nil, err
	}
	return projects, nil
}

func (c *OCIClient) harborListProjectRepositories(ctx context.Context, registry *entity.Registry, projectName string) ([]harborRepository, error) {
	var repositories []harborRepository
	path := "/api/v2.0/projects/" + url.PathEscape(projectName) + "/repositories"
	if err := c.harborGetPaged(ctx, registry, path, nil, &repositories); err != nil {
		return nil, err
	}
	return repositories, nil
}

func (c *OCIClient) listHarborArtifacts(ctx context.Context, registry *entity.Registry, repository, mediaTypeFilter string) ([]*entity.Artifact, error) {
	projectName, repoName, ok := splitHarborRepository(repository)
	if !ok {
		return nil, fmt.Errorf("repository %q is not a Harbor project repository path", repository)
	}

	var harborArtifacts []harborArtifact
	path := "/api/v2.0/projects/" + url.PathEscape(projectName) + "/repositories/" + url.PathEscape(repoName) + "/artifacts"
	query := url.Values{
		"with_tag":   []string{"true"},
		"with_label": []string{"false"},
	}
	if err := c.harborGetPaged(ctx, registry, path, query, &harborArtifacts); err != nil {
		return nil, err
	}

	artifacts := make([]*entity.Artifact, 0)
	for _, harborArtifact := range harborArtifacts {
		tags := harborArtifact.Tags
		if len(tags) == 0 {
			continue
		}

		for _, tag := range tags {
			if strings.TrimSpace(tag.Name) == "" {
				continue
			}
			artifact := &entity.Artifact{
				Repository:  repository,
				Tag:         tag.Name,
				Digest:      harborArtifact.Digest,
				MediaType:   harborArtifact.MediaType,
				ConfigType:  harborArtifact.ArtifactType,
				Size:        harborArtifact.Size,
				Annotations: harborArtifact.Annotations,
				CreatedAt:   parseHarborTime(firstNonEmpty(tag.PushTime, harborArtifact.PushTime)),
			}
			if artifact.Annotations == nil {
				artifact.Annotations = make(map[string]string)
			}

			artifact.DetermineType()
			if isHarborChartArtifact(harborArtifact) {
				artifact.Type = entity.ArtifactTypeChart
			}

			if c.shouldIncludeArtifact(artifact, mediaTypeFilter) {
				artifacts = append(artifacts, artifact)
			}
		}
	}

	return artifacts, nil
}

func (c *OCIClient) harborGetPaged(ctx context.Context, registry *entity.Registry, path string, query url.Values, target interface{}) error {
	const pageSize = 100

	accumulated := make([]json.RawMessage, 0)
	for page := 1; ; page++ {
		pageQuery := cloneValues(query)
		pageQuery.Set("page", fmt.Sprintf("%d", page))
		pageQuery.Set("page_size", fmt.Sprintf("%d", pageSize))

		body, total, err := c.harborGet(ctx, registry, path, pageQuery)
		if err != nil {
			return err
		}

		var pageItems []json.RawMessage
		if err := json.Unmarshal(body, &pageItems); err != nil {
			return fmt.Errorf("failed to decode Harbor response for %s: %w", path, err)
		}
		accumulated = append(accumulated, pageItems...)

		if len(pageItems) < pageSize || (total >= 0 && len(accumulated) >= total) {
			break
		}
	}

	combined, err := json.Marshal(accumulated)
	if err != nil {
		return fmt.Errorf("failed to combine Harbor pages: %w", err)
	}
	if err := json.Unmarshal(combined, target); err != nil {
		return fmt.Errorf("failed to decode Harbor pages: %w", err)
	}
	return nil
}

func (c *OCIClient) harborGet(ctx context.Context, registry *entity.Registry, path string, query url.Values) ([]byte, int, error) {
	baseURL, err := harborBaseURL(registry)
	if err != nil {
		return nil, -1, err
	}

	requestURL := strings.TrimRight(baseURL, "/") + path
	if len(query) > 0 {
		requestURL += "?" + query.Encode()
	}

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)
	if err != nil {
		return nil, -1, err
	}
	req.Header.Set("Accept", "application/json")
	if registry.Username != "" || registry.Password != "" {
		req.SetBasicAuth(registry.Username, registry.Password)
	}

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, -1, fmt.Errorf("Harbor API request failed: %w", err)
	}
	defer resp.Body.Close()

	body, readErr := io.ReadAll(io.LimitReader(resp.Body, 10*1024*1024))
	if readErr != nil {
		return nil, -1, fmt.Errorf("failed to read Harbor API response: %w", readErr)
	}
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, -1, fmt.Errorf("Harbor API %s returned %d: %s", path, resp.StatusCode, strings.TrimSpace(string(body)))
	}

	total := -1
	if value := strings.TrimSpace(resp.Header.Get("X-Total-Count")); value != "" {
		if parsed, err := strconv.Atoi(value); err == nil {
			total = parsed
		}
	}
	return body, total, nil
}

func harborBaseURL(registry *entity.Registry) (string, error) {
	rawURL := strings.TrimSpace(registry.URL)
	if rawURL == "" {
		return "", fmt.Errorf("registry URL is empty")
	}
	if !strings.Contains(rawURL, "://") {
		rawURL = "https://" + rawURL
	}
	parsed, err := url.Parse(rawURL)
	if err != nil {
		return "", fmt.Errorf("invalid registry URL %q: %w", registry.URL, err)
	}
	if parsed.Scheme == "" || parsed.Host == "" {
		return "", fmt.Errorf("invalid registry URL %q", registry.URL)
	}
	return parsed.Scheme + "://" + parsed.Host, nil
}

func splitHarborRepository(repository string) (string, string, bool) {
	projectName, repoName, ok := strings.Cut(strings.Trim(repository, "/"), "/")
	if !ok || projectName == "" || repoName == "" {
		return "", "", false
	}
	return projectName, repoName, true
}

func normalizeHarborRepositoryName(projectName, repositoryName string) string {
	repositoryName = strings.Trim(repositoryName, "/")
	if repositoryName == "" {
		return ""
	}
	if strings.HasPrefix(repositoryName, projectName+"/") {
		return repositoryName
	}
	return projectName + "/" + repositoryName
}

func isHarborChartArtifact(artifact harborArtifact) bool {
	typeInfo := strings.ToLower(strings.TrimSpace(artifact.ArtifactType + " " + artifact.MediaType))
	return strings.Contains(typeInfo, "chart") || strings.Contains(typeInfo, "helm")
}

func cloneValues(values url.Values) url.Values {
	cloned := make(url.Values)
	for key, items := range values {
		cloned[key] = append([]string(nil), items...)
	}
	return cloned
}

func firstNonEmpty(values ...string) string {
	for _, value := range values {
		if strings.TrimSpace(value) != "" {
			return value
		}
	}
	return ""
}

func parseHarborTime(value string) time.Time {
	value = strings.TrimSpace(value)
	if value == "" {
		return time.Time{}
	}
	for _, layout := range []string{time.RFC3339Nano, time.RFC3339, "2006-01-02T15:04:05.999999", "2006-01-02T15:04:05"} {
		if parsed, err := time.Parse(layout, value); err == nil {
			return parsed
		}
	}
	return time.Time{}
}

// ListArtifacts 列出指定 repository 的所有 artifacts
// mediaTypeFilter: "all", "image", "chart", "other" - 使用模糊匹配过滤
func (c *OCIClient) ListArtifacts(ctx context.Context, registry *entity.Registry, repository, mediaTypeFilter string) ([]*entity.Artifact, error) {
	if artifacts, err := c.listHarborArtifacts(ctx, registry, repository, mediaTypeFilter); err == nil {
		return artifacts, nil
	}

	reg, err := c.getRegistry(registry)
	if err != nil {
		return nil, err
	}

	repo, err := reg.Repository(ctx, repository)
	if err != nil {
		return nil, fmt.Errorf("failed to get repository: %w", err)
	}

	artifacts := make([]*entity.Artifact, 0)

	err = repo.Tags(ctx, "", func(tags []string) error {
		for _, tag := range tags {
			// 获取 manifest 以获取更多信息
			desc, err := repo.Resolve(ctx, tag)
			if err != nil {
				// 跳过无法解析的 tag
				continue
			}

			artifact := &entity.Artifact{
				Repository: repository,
				Tag:        tag,
				Digest:     desc.Digest.String(),
				MediaType:  desc.MediaType,
				Size:       desc.Size,
			}

			// 尝试获取 config.mediaType 以更准确判断类型
			if manifestBytes, err := repo.Fetch(ctx, desc); err == nil {
				defer manifestBytes.Close()
				if manifestData, err := io.ReadAll(manifestBytes); err == nil {
					var manifest map[string]interface{}
					if err := json.Unmarshal(manifestData, &manifest); err == nil {
						// 获取 config.mediaType
						if config, ok := manifest["config"].(map[string]interface{}); ok {
							if configMediaType, ok := config["mediaType"].(string); ok {
								artifact.ConfigType = configMediaType
							}
						}
					}
				}
			}

			// 使用智能类型判断（综合多种信息）
			artifact.DetermineType()

			// 应用 mediaType 过滤
			if c.shouldIncludeArtifact(artifact, mediaTypeFilter) {
				artifacts = append(artifacts, artifact)
			}
		}
		return nil
	})

	if err != nil {
		return nil, fmt.Errorf("failed to list artifacts: %w", err)
	}

	return artifacts, nil
}

// shouldIncludeArtifact 判断是否应该包含该 artifact
func (c *OCIClient) shouldIncludeArtifact(artifact *entity.Artifact, filter string) bool {
	// 默认或 "all" 返回所有
	if filter == "" || filter == "all" {
		return true
	}

	filter = strings.ToLower(strings.TrimSpace(filter))

	switch filter {
	case "chart":
		// 只返回 Helm Charts
		return artifact.Type == entity.ArtifactTypeChart
	case "image":
		// 返回 Docker 或 OCI images
		return artifact.Type == entity.ArtifactTypeImage
	case "other":
		// 返回其他类型
		return artifact.Type == entity.ArtifactTypeOther
	default:
		// 未知的 filter，返回所有
		return true
	}
}

// GetArtifact 获取指定 artifact 的详细信息
func (c *OCIClient) GetArtifact(ctx context.Context, registry *entity.Registry, repository, reference string) (*entity.Artifact, error) {
	reg, err := c.getRegistry(registry)
	if err != nil {
		return nil, err
	}

	repo, err := reg.Repository(ctx, repository)
	if err != nil {
		return nil, fmt.Errorf("failed to get repository: %w", err)
	}

	// 解析 reference
	desc, err := repo.Resolve(ctx, reference)
	if err != nil {
		return nil, fmt.Errorf("failed to resolve artifact: %w", err)
	}

	// 获取 manifest
	manifestBytes, err := repo.Fetch(ctx, desc)
	if err != nil {
		return nil, fmt.Errorf("failed to fetch manifest: %w", err)
	}
	defer manifestBytes.Close()

	manifestData, err := io.ReadAll(manifestBytes)
	if err != nil {
		return nil, fmt.Errorf("failed to read manifest: %w", err)
	}

	// 解析 manifest 获取配置信息
	var manifest map[string]interface{}
	if err := json.Unmarshal(manifestData, &manifest); err != nil {
		return nil, fmt.Errorf("failed to unmarshal manifest: %w", err)
	}

	artifact := &entity.Artifact{
		Repository:  repository,
		Tag:         reference,
		Digest:      desc.Digest.String(),
		MediaType:   desc.MediaType,
		Size:        desc.Size,
		Annotations: make(map[string]string),
	}

	// 获取 config.mediaType 和 annotations
	if config, ok := manifest["config"].(map[string]interface{}); ok {
		// 获取 config.mediaType（用于准确的类型判断）
		if configMediaType, ok := config["mediaType"].(string); ok {
			artifact.ConfigType = configMediaType
		}

		// 获取 annotations
		if annotations, ok := config["annotations"].(map[string]interface{}); ok {
			for k, v := range annotations {
				if str, ok := v.(string); ok {
					artifact.Annotations[k] = str
				}
			}
		}
	}

	// 使用智能类型判断（综合 ConfigType, Annotations, Repository 名称等）
	artifact.DetermineType()

	return artifact, nil
}

// GetValuesSchema 获取 Helm Chart 的 values schema
func (c *OCIClient) GetValuesSchema(ctx context.Context, registry *entity.Registry, repository, reference string) (string, error) {
	reg, err := c.getRegistry(registry)
	if err != nil {
		return "", err
	}

	repo, err := reg.Repository(ctx, repository)
	if err != nil {
		return "", fmt.Errorf("failed to get repository: %w", err)
	}

	// 解析 reference (tag 或 digest)
	desc, err := repo.Resolve(ctx, reference)
	if err != nil {
		return "", fmt.Errorf("failed to resolve artifact: %w", err)
	}

	manifestReader, err := repo.Fetch(ctx, desc)
	if err != nil {
		return "", fmt.Errorf("failed to fetch manifest: %w", err)
	}
	defer manifestReader.Close()

	manifestBytes, err := io.ReadAll(manifestReader)
	if err != nil {
		return "", fmt.Errorf("failed to read manifest: %w", err)
	}

	var manifest ocispec.Manifest
	if err := json.Unmarshal(manifestBytes, &manifest); err != nil {
		return "", fmt.Errorf("failed to unmarshal manifest: %w", err)
	}

	// 优先查找是否存在独立的 values schema layer（一些 registry 会将 values.schema.json 作为单独的 layer 存储）
	var valuesSchemaLayer *ocispec.Descriptor
	for i := range manifest.Layers {
		layer := manifest.Layers[i]
		mediaType := strings.ToLower(layer.MediaType)

		if strings.Contains(mediaType, "helm.values.schema") ||
			strings.Contains(mediaType, "values.schema") {
			valuesSchemaLayer = &manifest.Layers[i]
			break
		}
	}

	// 如果存在独立的 values schema layer，直接返回
	if valuesSchemaLayer != nil {
		reader, err := repo.Fetch(ctx, *valuesSchemaLayer)
		if err != nil {
			return "", fmt.Errorf("failed to fetch values schema layer: %w", err)
		}
		defer reader.Close()

		data, err := io.ReadAll(reader)
		if err != nil {
			return "", fmt.Errorf("failed to read values schema layer: %w", err)
		}

		if len(data) == 0 {
			return "", entity.ErrValuesSchemaNotFound
		}

		return string(data), nil
	}

	// 回退：查找 Helm Chart layer（tar+gzip 包含 chart 内容）并从中读取 values.schema.json
	var chartLayer *ocispec.Descriptor
	for i := range manifest.Layers {
		layer := manifest.Layers[i]
		if strings.Contains(layer.MediaType, "cncf.helm.chart") ||
			strings.Contains(layer.MediaType, "helm.chart.content") {
			chartLayer = &manifest.Layers[i]
			break
		}
	}

	if chartLayer == nil {
		return "", entity.ErrValuesSchemaNotFound
	}

	if chartLayer.Digest == "" {
		return "", fmt.Errorf("chart layer digest is empty")
	}
	if _, err := digest.Parse(string(chartLayer.Digest)); err != nil {
		return "", fmt.Errorf("invalid chart layer digest: %w", err)
	}

	layerReader, err := repo.Fetch(ctx, *chartLayer)
	if err != nil {
		return "", fmt.Errorf("failed to fetch chart layer: %w", err)
	}
	defer layerReader.Close()

	gzipReader, err := gzip.NewReader(layerReader)
	if err != nil {
		return "", fmt.Errorf("failed to create gzip reader: %w", err)
	}
	defer gzipReader.Close()

	tarReader := tar.NewReader(gzipReader)
	for {
		header, err := tarReader.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return "", fmt.Errorf("failed to read chart archive: %w", err)
		}

		if header.Typeflag != tar.TypeReg {
			continue
		}

		if strings.HasSuffix(header.Name, "values.schema.json") {
			data, err := io.ReadAll(tarReader)
			if err != nil {
				return "", fmt.Errorf("failed to read values.schema.json: %w", err)
			}
			if len(data) == 0 {
				return "", entity.ErrValuesSchemaNotFound
			}
			return string(data), nil
		}
	}

	return "", entity.ErrValuesSchemaNotFound
}

// GetValuesYAML 获取 Helm Chart 包内原始 values.yaml
func (c *OCIClient) GetValuesYAML(ctx context.Context, registry *entity.Registry, repository, reference string) (string, error) {
	data, err := c.readChartFile(ctx, registry, repository, reference, "values.yaml")
	if err != nil {
		return "", err
	}
	if strings.TrimSpace(data) == "" {
		return "", entity.ErrArtifactNotFound
	}
	return data, nil
}

func (c *OCIClient) readChartFile(ctx context.Context, registry *entity.Registry, repository, reference, filename string) (string, error) {
	reg, err := c.getRegistry(registry)
	if err != nil {
		return "", err
	}

	repo, err := reg.Repository(ctx, repository)
	if err != nil {
		return "", fmt.Errorf("failed to get repository: %w", err)
	}

	desc, err := repo.Resolve(ctx, reference)
	if err != nil {
		return "", fmt.Errorf("failed to resolve artifact: %w", err)
	}

	manifestReader, err := repo.Fetch(ctx, desc)
	if err != nil {
		return "", fmt.Errorf("failed to fetch manifest: %w", err)
	}
	defer manifestReader.Close()

	manifestBytes, err := io.ReadAll(manifestReader)
	if err != nil {
		return "", fmt.Errorf("failed to read manifest: %w", err)
	}

	var manifest ocispec.Manifest
	if err := json.Unmarshal(manifestBytes, &manifest); err != nil {
		return "", fmt.Errorf("failed to unmarshal manifest: %w", err)
	}

	var chartLayer *ocispec.Descriptor
	for i := range manifest.Layers {
		layer := manifest.Layers[i]
		if strings.Contains(layer.MediaType, "cncf.helm.chart") ||
			strings.Contains(layer.MediaType, "helm.chart.content") {
			chartLayer = &manifest.Layers[i]
			break
		}
	}
	if chartLayer == nil {
		return "", fmt.Errorf("helm chart layer not found in manifest")
	}
	if chartLayer.Digest == "" {
		return "", fmt.Errorf("chart layer digest is empty")
	}
	if _, err := digest.Parse(string(chartLayer.Digest)); err != nil {
		return "", fmt.Errorf("invalid chart layer digest: %w", err)
	}

	layerReader, err := repo.Fetch(ctx, *chartLayer)
	if err != nil {
		return "", fmt.Errorf("failed to fetch chart layer: %w", err)
	}
	defer layerReader.Close()

	gzipReader, err := gzip.NewReader(layerReader)
	if err != nil {
		return "", fmt.Errorf("failed to create gzip reader: %w", err)
	}
	defer gzipReader.Close()

	tarReader := tar.NewReader(gzipReader)
	bestDepth := int(^uint(0) >> 1)
	var bestData []byte
	for {
		header, err := tarReader.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return "", fmt.Errorf("failed to read chart archive: %w", err)
		}
		if header.Typeflag != tar.TypeReg {
			continue
		}
		if strings.HasSuffix(header.Name, filename) {
			data, err := io.ReadAll(tarReader)
			if err != nil {
				return "", fmt.Errorf("failed to read %s: %w", filename, err)
			}
			depth := strings.Count(strings.Trim(header.Name, "/"), "/")
			if depth < bestDepth {
				bestDepth = depth
				bestData = data
			}
		}
	}
	if len(bestData) > 0 {
		return string(bestData), nil
	}
	return "", fmt.Errorf("%s not found in chart", filename)
}

// PullArtifact 下载 artifact 到本地
func (c *OCIClient) PullArtifact(ctx context.Context, registry *entity.Registry, repository, reference, destPath string) error {
	reg, err := c.getRegistry(registry)
	if err != nil {
		return err
	}

	repo, err := reg.Repository(ctx, repository)
	if err != nil {
		return fmt.Errorf("failed to get repository: %w", err)
	}

	// 解析 reference
	desc, err := repo.Resolve(ctx, reference)
	if err != nil {
		return fmt.Errorf("failed to resolve artifact: %w", err)
	}

	// 获取 manifest 内容
	manifestReader, err := repo.Fetch(ctx, desc)
	if err != nil {
		return fmt.Errorf("failed to fetch manifest: %w", err)
	}
	defer manifestReader.Close()

	manifestBytes, err := io.ReadAll(manifestReader)
	if err != nil {
		return fmt.Errorf("failed to read manifest: %w", err)
	}

	var manifest ocispec.Manifest
	if err := json.Unmarshal(manifestBytes, &manifest); err != nil {
		return fmt.Errorf("failed to unmarshal manifest: %w", err)
	}

	var chartLayer *ocispec.Descriptor
	for i := range manifest.Layers {
		layer := manifest.Layers[i]
		if strings.Contains(layer.MediaType, "cncf.helm.chart") ||
			strings.Contains(layer.MediaType, "helm.chart.content") {
			chartLayer = &layer
			break
		}
	}

	if chartLayer == nil {
		return fmt.Errorf("helm chart layer not found in manifest")
	}

	content, err := repo.Fetch(ctx, *chartLayer)
	if err != nil {
		return fmt.Errorf("failed to fetch chart layer: %w", err)
	}
	defer content.Close()

	// 确保目标目录存在
	if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil {
		return fmt.Errorf("failed to create destination directory: %w", err)
	}

	// 写入文件
	file, err := os.Create(destPath)
	if err != nil {
		return fmt.Errorf("failed to create file: %w", err)
	}
	defer file.Close()

	if _, err := io.Copy(file, content); err != nil {
		return fmt.Errorf("failed to write artifact: %w", err)
	}

	return nil
}

// PushArtifact 推送 artifact 到 Registry
func (c *OCIClient) PushArtifact(ctx context.Context, registry *entity.Registry, repository, tag, sourcePath string) error {
	// 这是一个简化实现
	// 实际应该实现完整的 OCI artifact push 流程
	return fmt.Errorf("push artifact not fully implemented yet")
}

// CheckHealth 检查 Registry 健康状态
func (c *OCIClient) CheckHealth(ctx context.Context, registry *entity.Registry) error {
	reg, err := c.getRegistry(registry)
	if err != nil {
		return err
	}

	// 尝试 ping registry
	err = reg.Ping(ctx)
	if err != nil {
		return fmt.Errorf("registry health check failed: %w", err)
	}

	return nil
}
