package httpapi

import (
	"encoding/json"
	"net/http"
	"strings"

	"github.com/easyai/easyai-ai-gateway/apps/api/internal/store"
)

// listFileStorageChannels godoc
// @Summary 列出文件存储通道
// @Description 返回所有未删除的文件存储通道，用于管理上传与生成资源回传策略。
// @Tags system
// @Produce json
// @Security BearerAuth
// @Success 200 {object} FileStorageChannelListResponse
// @Failure 401 {object} ErrorEnvelope
// @Failure 403 {object} ErrorEnvelope
// @Failure 500 {object} ErrorEnvelope
// @Router /api/admin/system/file-storage/channels [get]
func (s *Server) listFileStorageChannels(w http.ResponseWriter, r *http.Request) {
	items, err := s.store.ListFileStorageChannels(r.Context())
	if err != nil {
		s.logger.Error("list file storage channels failed", "error", err)
		writeError(w, http.StatusInternalServerError, "list file storage channels failed")
		return
	}
	writeJSON(w, http.StatusOK, map[string]any{"items": items})
}

// getFileStorageSettings godoc
// @Summary 获取文件存储设置
// @Description 返回文件存储系统设置；数据库对象尚未创建时返回默认设置。
// @Tags system
// @Produce json
// @Security BearerAuth
// @Success 200 {object} store.FileStorageSettings
// @Failure 401 {object} ErrorEnvelope
// @Failure 403 {object} ErrorEnvelope
// @Failure 500 {object} ErrorEnvelope
// @Router /api/admin/system/file-storage/settings [get]
func (s *Server) getFileStorageSettings(w http.ResponseWriter, r *http.Request) {
	settings, err := s.store.GetFileStorageSettings(r.Context())
	if err != nil {
		if store.IsUndefinedDatabaseObject(err) {
			writeJSON(w, http.StatusOK, store.DefaultFileStorageSettings())
			return
		}
		s.logger.Error("get file storage settings failed", "error", err)
		writeError(w, http.StatusInternalServerError, "get file storage settings failed")
		return
	}
	writeJSON(w, http.StatusOK, settings)
}

// updateFileStorageSettings godoc
// @Summary 更新文件存储设置
// @Description 更新生成资源上传策略等文件存储系统设置。
// @Tags system
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param body body store.FileStorageSettingsInput true "文件存储设置"
// @Success 200 {object} store.FileStorageSettings
// @Failure 400 {object} ErrorEnvelope
// @Failure 401 {object} ErrorEnvelope
// @Failure 403 {object} ErrorEnvelope
// @Failure 500 {object} ErrorEnvelope
// @Router /api/admin/system/file-storage/settings [patch]
func (s *Server) updateFileStorageSettings(w http.ResponseWriter, r *http.Request) {
	var input store.FileStorageSettingsInput
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		writeError(w, http.StatusBadRequest, "invalid json body")
		return
	}
	settings, err := s.store.UpdateFileStorageSettings(r.Context(), input)
	if err != nil {
		s.logger.Error("update file storage settings failed", "error", err)
		writeError(w, http.StatusInternalServerError, "update file storage settings failed")
		return
	}
	writeJSON(w, http.StatusOK, settings)
}

// getClientCustomizationSettings godoc
// @Summary 获取客户端自定义设置
// @Description 返回客户端名称、英文名称、平台名和图标路径；数据库对象尚未创建时返回默认设置。
// @Tags system
// @Produce json
// @Security BearerAuth
// @Success 200 {object} store.ClientCustomizationSettings
// @Failure 401 {object} ErrorEnvelope
// @Failure 403 {object} ErrorEnvelope
// @Failure 500 {object} ErrorEnvelope
// @Router /api/admin/system/client-customization/settings [get]
func (s *Server) getClientCustomizationSettings(w http.ResponseWriter, r *http.Request) {
	s.writeClientCustomizationSettings(w, r)
}

// getPublicClientCustomizationSettings godoc
// @Summary 获取公开客户端自定义设置
// @Description 无需鉴权返回客户端名称、英文名称、平台名和图标路径；数据库对象尚未创建时返回默认设置。
// @Tags system
// @Produce json
// @Success 200 {object} store.ClientCustomizationSettings
// @Failure 500 {object} ErrorEnvelope
// @Router /api/v1/public/client-customization [get]
func (s *Server) getPublicClientCustomizationSettings(w http.ResponseWriter, r *http.Request) {
	s.writeClientCustomizationSettings(w, r)
}

func (s *Server) writeClientCustomizationSettings(w http.ResponseWriter, r *http.Request) {
	settings, err := s.store.GetClientCustomizationSettings(r.Context())
	if err != nil {
		if store.IsUndefinedDatabaseObject(err) {
			writeJSON(w, http.StatusOK, store.DefaultClientCustomizationSettings())
			return
		}
		s.logger.Error("get client customization settings failed", "error", err)
		writeError(w, http.StatusInternalServerError, "get client customization settings failed")
		return
	}
	writeJSON(w, http.StatusOK, settings)
}

// updateClientCustomizationSettings godoc
// @Summary 更新客户端自定义设置
// @Description 更新客户端名称、英文名称、平台名和图标路径。
// @Tags system
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param body body store.ClientCustomizationSettingsInput true "客户端自定义设置"
// @Success 200 {object} store.ClientCustomizationSettings
// @Failure 400 {object} ErrorEnvelope
// @Failure 401 {object} ErrorEnvelope
// @Failure 403 {object} ErrorEnvelope
// @Failure 500 {object} ErrorEnvelope
// @Router /api/admin/system/client-customization/settings [patch]
func (s *Server) updateClientCustomizationSettings(w http.ResponseWriter, r *http.Request) {
	var input store.ClientCustomizationSettingsInput
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		writeError(w, http.StatusBadRequest, "invalid json body")
		return
	}
	settings, err := s.store.UpdateClientCustomizationSettings(r.Context(), input)
	if err != nil {
		s.logger.Error("update client customization settings failed", "error", err)
		writeError(w, http.StatusInternalServerError, "update client customization settings failed")
		return
	}
	writeJSON(w, http.StatusOK, settings)
}

// createFileStorageChannel godoc
// @Summary 创建文件存储通道
// @Description 创建文件存储通道，当前主要用于配置 server-main OpenAPI 上传通道。
// @Tags system
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param body body store.FileStorageChannelInput true "文件存储通道"
// @Success 201 {object} store.FileStorageChannel
// @Failure 400 {object} ErrorEnvelope
// @Failure 401 {object} ErrorEnvelope
// @Failure 403 {object} ErrorEnvelope
// @Failure 409 {object} ErrorEnvelope
// @Failure 500 {object} ErrorEnvelope
// @Router /api/admin/system/file-storage/channels [post]
func (s *Server) createFileStorageChannel(w http.ResponseWriter, r *http.Request) {
	var input store.FileStorageChannelInput
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		writeError(w, http.StatusBadRequest, "invalid json body")
		return
	}
	if message := validateFileStorageChannelInput(input, nil); message != "" {
		writeError(w, http.StatusBadRequest, message)
		return
	}
	item, err := s.store.CreateFileStorageChannel(r.Context(), input)
	if err != nil {
		if store.IsUniqueViolation(err) {
			writeError(w, http.StatusConflict, "file storage channel key already exists")
			return
		}
		s.logger.Error("create file storage channel failed", "error", err)
		writeError(w, http.StatusInternalServerError, "create file storage channel failed")
		return
	}
	writeJSON(w, http.StatusCreated, item)
}

// updateFileStorageChannel godoc
// @Summary 更新文件存储通道
// @Description 更新指定文件存储通道的名称、凭证、场景、优先级、状态和重试策略。
// @Tags system
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param channelID path string true "文件存储通道 ID"
// @Param body body store.FileStorageChannelInput true "文件存储通道"
// @Success 200 {object} store.FileStorageChannel
// @Failure 400 {object} ErrorEnvelope
// @Failure 401 {object} ErrorEnvelope
// @Failure 403 {object} ErrorEnvelope
// @Failure 404 {object} ErrorEnvelope
// @Failure 409 {object} ErrorEnvelope
// @Failure 500 {object} ErrorEnvelope
// @Router /api/admin/system/file-storage/channels/{channelID} [patch]
func (s *Server) updateFileStorageChannel(w http.ResponseWriter, r *http.Request) {
	var input store.FileStorageChannelInput
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		writeError(w, http.StatusBadRequest, "invalid json body")
		return
	}
	existing, err := s.store.GetFileStorageChannel(r.Context(), r.PathValue("channelID"))
	if err != nil {
		if store.IsNotFound(err) {
			writeError(w, http.StatusNotFound, "file storage channel not found")
			return
		}
		s.logger.Error("get file storage channel failed", "error", err)
		writeError(w, http.StatusInternalServerError, "get file storage channel failed")
		return
	}
	if message := validateFileStorageChannelInput(input, &existing); message != "" {
		writeError(w, http.StatusBadRequest, message)
		return
	}
	item, err := s.store.UpdateFileStorageChannel(r.Context(), r.PathValue("channelID"), input)
	if err != nil {
		if store.IsNotFound(err) {
			writeError(w, http.StatusNotFound, "file storage channel not found")
			return
		}
		if store.IsUniqueViolation(err) {
			writeError(w, http.StatusConflict, "file storage channel key already exists")
			return
		}
		s.logger.Error("update file storage channel failed", "error", err)
		writeError(w, http.StatusInternalServerError, "update file storage channel failed")
		return
	}
	writeJSON(w, http.StatusOK, item)
}

// deleteFileStorageChannel godoc
// @Summary 删除文件存储通道
// @Description 软删除指定文件存储通道。
// @Tags system
// @Produce json
// @Security BearerAuth
// @Param channelID path string true "文件存储通道 ID"
// @Success 204 "No Content"
// @Failure 401 {object} ErrorEnvelope
// @Failure 403 {object} ErrorEnvelope
// @Failure 404 {object} ErrorEnvelope
// @Failure 500 {object} ErrorEnvelope
// @Router /api/admin/system/file-storage/channels/{channelID} [delete]
func (s *Server) deleteFileStorageChannel(w http.ResponseWriter, r *http.Request) {
	if err := s.store.DeleteFileStorageChannel(r.Context(), r.PathValue("channelID")); err != nil {
		if store.IsNotFound(err) {
			writeError(w, http.StatusNotFound, "file storage channel not found")
			return
		}
		s.logger.Error("delete file storage channel failed", "error", err)
		writeError(w, http.StatusInternalServerError, "delete file storage channel failed")
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

func validateFileStorageChannelInput(input store.FileStorageChannelInput, existing *store.FileStorageChannel) string {
	provider := strings.ToLower(strings.TrimSpace(input.Provider))
	if provider == "" {
		provider = "server_main_openapi"
	}
	status := strings.ToLower(strings.TrimSpace(input.Status))
	if status == "" {
		status = "disabled"
	}
	if strings.TrimSpace(input.ChannelKey) == "" || strings.TrimSpace(input.Name) == "" {
		return "channelKey and name are required"
	}
	if status != "enabled" && status != "disabled" {
		return "status must be enabled or disabled"
	}
	if provider == "server_main_openapi" {
		hasAPIKey := false
		if input.APIKey != nil {
			hasAPIKey = strings.TrimSpace(*input.APIKey) != ""
		} else if existing != nil {
			hasAPIKey = strings.TrimSpace(existing.APIKey) != ""
		}
		if status == "enabled" && !hasAPIKey {
			return "server-main OpenAPI channel requires API key before enabling"
		}
	}
	return ""
}
