package rest

import (
	"errors"
	"net/http"

	"github.com/gorilla/mux"
	"github.com/ocdp/cluster-service/internal/adapter/input/http/dto"
	"github.com/ocdp/cluster-service/internal/domain/entity"
	"github.com/ocdp/cluster-service/internal/domain/service"
)

// ArtifactHandler Artifact Handler
type ArtifactHandler struct {
	artifactService *service.ArtifactService
}

// NewArtifactHandler 创建 Artifact Handler
func NewArtifactHandler(artifactService *service.ArtifactService) *ArtifactHandler {
	return &ArtifactHandler{
		artifactService: artifactService,
	}
}

// ListRepositories 列出 Registry 中的所有 repositories
// @Summary 列出 Registry 中的所有 Repositories
// @Description 列出指定 Registry 中的所有 Repository
// @Tags Artifacts
// @Accept json
// @Produce json
// @Param registry_id path string true "Registry ID"
// @Param artifact_type query string false "Artifact type filter (chart, all)" default(chart)
// @Success 200 {object} dto.RepositoryListResponse
// @Failure 500 {object} dto.ErrorResponse
// @Router /registries/{registry_id}/repositories [get]
func (h *ArtifactHandler) ListRepositories(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	registryID := vars["registry_id"]
	artifactType := r.URL.Query().Get("artifact_type")
	if artifactType == "" {
		artifactType = "chart"
	}

	repositories, err := h.artifactService.ListRepositories(r.Context(), registryID, artifactType)
	if err != nil {
		respondError(w, http.StatusInternalServerError, "Failed to list repositories", err.Error())
		return
	}

	// Get registry info for URL
	registry, err := h.artifactService.GetRegistry(r.Context(), registryID)
	registryURL := ""
	if err == nil && registry != nil {
		registryURL = registry.URL
	}

	// Determine source and message based on repository count
	source := "harbor-api"
	catalogSupported := true
	message := ""

	if len(repositories) == 0 {
		source = "unavailable"
		if artifactType == "chart" {
			message = "No chart repositories found in this registry"
		} else {
			message = "No repositories found in this registry"
		}
	}

	response := &dto.RepositoryListResponse{
		RegistryID:       registryID,
		RegistryURL:      registryURL,
		Repositories:     repositories,
		Total:            len(repositories),
		CatalogSupported: catalogSupported,
		Source:           source,
		Message:          message,
	}

	respondJSON(w, http.StatusOK, response)
}

// ListArtifacts 列出 repository 中的所有 artifacts（返回扁平化的 Tag 数组）
// @Summary 列出 Repository 中的所有 Artifacts
// @Description 列出指定 Repository 中的所有 Artifact，支持按类型过滤
// @Tags Artifacts
// @Accept json
// @Produce json
// @Param registry_id path string true "Registry ID"
// @Param repository_name path string true "Repository Name (URL encoded, e.g. charts%2Fnginx)"
// @Param media_type query string false "过滤 Artifact 类型 (all, chart, image, other)" default(all)
// @Success 200 {array} dto.TagResponse
// @Failure 500 {object} dto.ErrorResponse
// @Router /registries/{registry_id}/repositories/{repository_name}/artifacts [get]
func (h *ArtifactHandler) ListArtifacts(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	registryID := vars["registry_id"]
	repositoryName := vars["repository_name"]

	// 获取 mediaType 过滤参数（默认为 "all"）
	mediaTypeFilter := r.URL.Query().Get("media_type")
	if mediaTypeFilter == "" {
		mediaTypeFilter = "all"
	}

	artifacts, err := h.artifactService.ListArtifacts(r.Context(), registryID, repositoryName, mediaTypeFilter)
	if err != nil {
		respondError(w, http.StatusInternalServerError, "Failed to list artifacts", err.Error())
		return
	}

	// 转换为前端期望的扁平化 Tag 数组
	tagResponses := make([]*dto.TagResponse, 0, len(artifacts))
	for _, artifact := range artifacts {
		tagResponses = append(tagResponses, &dto.TagResponse{
			RepositoryName: artifact.Repository,
			Tag:            artifact.Tag,
			Type:           string(artifact.Type),
			MediaType:      artifact.MediaType,
			Size:           artifact.Size,
		})
	}

	// 直接返回数组，不包装
	respondJSON(w, http.StatusOK, tagResponses)
}

// ListRepositoryTags is a compatibility alias for clients that request tags
// directly instead of the canonical artifacts endpoint.
func (h *ArtifactHandler) ListRepositoryTags(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	if vars["registry_id"] == "" {
		registryID := r.URL.Query().Get("registry_id")
		if registryID == "" {
			registryID = r.URL.Query().Get("registryId")
		}
		if registryID == "" {
			respondError(w, http.StatusBadRequest, "Missing registry ID", "registry_id query parameter is required")
			return
		}
		vars["registry_id"] = registryID
		r = mux.SetURLVars(r, vars)
	}
	h.ListArtifacts(w, r)
}

// GetArtifact 获取 artifact 详情
// @Summary 获取 Artifact 详情
// @Description 获取指定 Artifact 的详细信息
// @Tags Artifacts
// @Accept json
// @Produce json
// @Param registry_id path string true "Registry ID"
// @Param repository_name path string true "Repository Name (URL encoded)"
// @Param reference path string true "Artifact Reference (tag or digest)"
// @Success 200 {object} dto.ArtifactResponse
// @Failure 404 {object} dto.ErrorResponse
// @Router /registries/{registry_id}/repositories/{repository_name}/artifacts/{reference} [get]
func (h *ArtifactHandler) GetArtifact(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	registryID := vars["registry_id"]
	repositoryName := vars["repository_name"]
	reference := vars["reference"]

	artifact, err := h.artifactService.GetArtifact(r.Context(), registryID, repositoryName, reference)
	if err != nil {
		respondError(w, http.StatusNotFound, "Artifact not found", err.Error())
		return
	}

	response := &dto.ArtifactResponse{
		RepositoryName: artifact.Repository,
		Tag:            artifact.Tag,
		Digest:         artifact.Digest,
		Type:           string(artifact.Type),
		Size:           artifact.Size,
		CreatedAt:      artifact.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
	}

	respondJSON(w, http.StatusOK, response)
}

// GetArtifactValuesSchema 获取 Helm Chart 的 values schema
// @Summary 获取 Helm Chart Values Schema
// @Description 获取 Helm Chart 的 values.schema.json (仅支持 Chart 类型)
// @Tags Artifacts
// @Accept json
// @Produce json
// @Param registry_id path string true "Registry ID"
// @Param repository_name path string true "Repository Name (URL encoded)"
// @Param reference path string true "Artifact Reference (tag or digest)"
// @Success 200 {object} dto.ValuesSchemaResponse
// @Failure 500 {object} dto.ErrorResponse
// @Router /registries/{registry_id}/repositories/{repository_name}/artifacts/{reference}/values-schema [get]
func (h *ArtifactHandler) GetArtifactValuesSchema(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	registryID := vars["registry_id"]
	repositoryName := vars["repository_name"]
	reference := vars["reference"]

	schema, err := h.artifactService.GetValuesSchema(r.Context(), registryID, repositoryName, reference)
	if err != nil {
		switch {
		case errors.Is(err, entity.ErrRegistryNotFound),
			errors.Is(err, entity.ErrRepositoryNotFound),
			errors.Is(err, entity.ErrArtifactNotFound),
			errors.Is(err, entity.ErrValuesSchemaNotFound):
			respondError(w, http.StatusNotFound, "Values schema not found", err.Error())
		default:
			respondError(w, http.StatusInternalServerError, "Failed to get values schema", err.Error())
		}
		return
	}

	response := &dto.ValuesSchemaResponse{
		Schema: schema,
	}

	respondJSON(w, http.StatusOK, response)
}

// GetArtifactValuesYAML 获取 Helm Chart 的默认 values.yaml
// @Summary 获取 Helm Chart 默认 Values YAML
// @Description 获取 Helm Chart 包内原始 values.yaml，用于高级覆盖编辑
// @Tags Artifacts
// @Accept json
// @Produce json
// @Param registry_id path string true "Registry ID"
// @Param repository_name path string true "Repository Name (URL encoded)"
// @Param reference path string true "Artifact Reference (tag or digest)"
// @Success 200 {object} dto.ValuesYAMLResponse
// @Failure 500 {object} dto.ErrorResponse
// @Router /registries/{registry_id}/repositories/{repository_name}/artifacts/{reference}/values-yaml [get]
func (h *ArtifactHandler) GetArtifactValuesYAML(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	registryID := vars["registry_id"]
	repositoryName := vars["repository_name"]
	reference := vars["reference"]

	valuesYAML, err := h.artifactService.GetValuesYAML(r.Context(), registryID, repositoryName, reference)
	if err != nil {
		switch {
		case errors.Is(err, entity.ErrRegistryNotFound),
			errors.Is(err, entity.ErrRepositoryNotFound),
			errors.Is(err, entity.ErrArtifactNotFound):
			respondError(w, http.StatusNotFound, "Values YAML not found", err.Error())
		default:
			respondError(w, http.StatusInternalServerError, "Failed to get values YAML", err.Error())
		}
		return
	}

	respondJSON(w, http.StatusOK, &dto.ValuesYAMLResponse{ValuesYAML: valuesYAML})
}
