package http

import (
	"fmt"
	"strconv"
	"strings"

	"backupx/server/internal/apperror"
	"backupx/server/internal/service"
	"backupx/server/pkg/response"
	"github.com/gin-gonic/gin"
)

type StorageTargetHandler struct {
	service      *service.StorageTargetService
	auditService *service.AuditService
}

type storageTargetGoogleDriveAuthRequest struct {
	TargetID     *uint          `json:"targetId"`
	Name         string         `json:"name"`
	Type         string         `json:"type"`
	Description  string         `json:"description"`
	Enabled      bool           `json:"enabled"`
	Config       map[string]any `json:"config"`
	ClientID     string         `json:"clientId"`
	ClientSecret string         `json:"clientSecret"`
	FolderID     string         `json:"folderId"`
}

func NewStorageTargetHandler(service *service.StorageTargetService, auditService *service.AuditService) *StorageTargetHandler {
	return &StorageTargetHandler{service: service, auditService: auditService}
}

func (h *StorageTargetHandler) List(c *gin.Context) {
	items, err := h.service.List(c.Request.Context())
	if err != nil {
		response.Error(c, err)
		return
	}
	response.Success(c, items)
}

func (h *StorageTargetHandler) Get(c *gin.Context) {
	id, ok := parseUintParam(c, "id")
	if !ok {
		return
	}
	item, err := h.service.Get(c.Request.Context(), id)
	if err != nil {
		response.Error(c, err)
		return
	}
	response.Success(c, item)
}

func (h *StorageTargetHandler) Create(c *gin.Context) {
	var input service.StorageTargetUpsertInput
	if err := c.ShouldBindJSON(&input); err != nil {
		response.Error(c, apperror.BadRequest("STORAGE_TARGET_INVALID", "存储目标参数不合法", err))
		return
	}
	item, err := h.service.Create(c.Request.Context(), input)
	if err != nil {
		response.Error(c, err)
		return
	}
	recordAudit(c, h.auditService, "storage_target", "create", "storage_target", fmt.Sprintf("%d", item.ID), item.Name,
		fmt.Sprintf("创建存储目标「%s」，类型: %s", item.Name, input.Type))
	response.Success(c, item)
}

func (h *StorageTargetHandler) Update(c *gin.Context) {
	id, ok := parseUintParam(c, "id")
	if !ok {
		return
	}
	var input service.StorageTargetUpsertInput
	if err := c.ShouldBindJSON(&input); err != nil {
		response.Error(c, apperror.BadRequest("STORAGE_TARGET_INVALID", "存储目标参数不合法", err))
		return
	}
	item, err := h.service.Update(c.Request.Context(), id, input)
	if err != nil {
		response.Error(c, err)
		return
	}
	recordAudit(c, h.auditService, "storage_target", "update", "storage_target", fmt.Sprintf("%d", item.ID), item.Name,
		fmt.Sprintf("更新存储目标「%s」，类型: %s", item.Name, input.Type))
	response.Success(c, item)
}

func (h *StorageTargetHandler) Delete(c *gin.Context) {
	id, ok := parseUintParam(c, "id")
	if !ok {
		return
	}
	if err := h.service.Delete(c.Request.Context(), id); err != nil {
		response.Error(c, err)
		return
	}
	recordAudit(c, h.auditService, "storage_target", "delete", "storage_target", fmt.Sprintf("%d", id), "",
		fmt.Sprintf("删除存储目标 (ID: %d)", id))
	response.Success(c, gin.H{"deleted": true})
}

func (h *StorageTargetHandler) TestConnection(c *gin.Context) {
	var payload service.StorageTargetUpsertInput
	if err := c.ShouldBindJSON(&payload); err != nil {
		response.Error(c, apperror.BadRequest("STORAGE_TARGET_TEST_INVALID", "测试连接参数不合法", err))
		return
	}
	if err := h.service.TestConnection(c.Request.Context(), service.StorageTargetTestInput{Payload: payload}); err != nil {
		response.Error(c, err)
		return
	}
	response.Success(c, gin.H{"success": true, "message": "连接成功"})
}

func (h *StorageTargetHandler) TestSavedConnection(c *gin.Context) {
	id, ok := parseUintParam(c, "id")
	if !ok {
		return
	}
	if err := h.service.TestConnection(c.Request.Context(), service.StorageTargetTestInput{TargetID: &id}); err != nil {
		response.Error(c, err)
		return
	}
	response.Success(c, gin.H{"success": true, "message": "连接成功"})
}

func (h *StorageTargetHandler) StartGoogleDriveOAuth(c *gin.Context) {
	var request storageTargetGoogleDriveAuthRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		response.Error(c, apperror.BadRequest("STORAGE_GOOGLE_OAUTH_INVALID", "Google Drive 授权参数不合法", err))
		return
	}
	input := service.GoogleDriveAuthStartInput{
		TargetID:     request.TargetID,
		Name:         strings.TrimSpace(request.Name),
		Description:  strings.TrimSpace(request.Description),
		Enabled:      request.Enabled,
		ClientID:     firstNonEmpty(asString(request.Config["clientId"]), request.ClientID),
		ClientSecret: firstNonEmpty(asString(request.Config["clientSecret"]), request.ClientSecret),
		FolderID:     firstNonEmpty(asString(request.Config["folderId"]), request.FolderID),
	}
	result, err := h.service.StartGoogleDriveOAuth(c.Request.Context(), input, requestOrigin(c))
	if err != nil {
		response.Error(c, err)
		return
	}
	response.Success(c, gin.H{"authUrl": result.AuthorizationURL})
}

func (h *StorageTargetHandler) CompleteGoogleDriveOAuth(c *gin.Context) {
	var input service.GoogleDriveAuthCompleteInput
	if err := c.ShouldBindJSON(&input); err != nil {
		response.Error(c, apperror.BadRequest("STORAGE_GOOGLE_OAUTH_INVALID", "Google Drive 回调参数不合法", err))
		return
	}
	item, err := h.service.CompleteGoogleDriveOAuth(c.Request.Context(), input)
	if err != nil {
		response.Error(c, err)
		return
	}
	response.Success(c, item)
}

func (h *StorageTargetHandler) HandleGoogleDriveCallback(c *gin.Context) {
	if queryError := strings.TrimSpace(c.Query("error")); queryError != "" {
		response.Success(c, gin.H{"success": false, "message": queryError})
		return
	}
	input := service.GoogleDriveAuthCompleteInput{State: strings.TrimSpace(c.Query("state")), Code: strings.TrimSpace(c.Query("code"))}
	if input.State == "" || input.Code == "" {
		response.Error(c, apperror.BadRequest("STORAGE_GOOGLE_OAUTH_INVALID", "Google Drive 回调参数不合法", nil))
		return
	}
	item, err := h.service.CompleteGoogleDriveOAuth(c.Request.Context(), input)
	if err != nil {
		response.Error(c, err)
		return
	}
	response.Success(c, gin.H{"success": true, "message": "Google Drive 授权成功", "target": item})
}

func (h *StorageTargetHandler) GoogleDriveProfile(c *gin.Context) {
	id, ok := parseUintParam(c, "id")
	if !ok {
		return
	}
	profile, err := h.service.GoogleDriveProfile(c.Request.Context(), id)
	if err != nil {
		response.Error(c, err)
		return
	}
	response.Success(c, profile)
}

func parseUintParam(c *gin.Context, key string) (uint, bool) {
	value := strings.TrimSpace(c.Param(key))
	parsed, err := strconv.ParseUint(value, 10, 64)
	if err != nil {
		response.Error(c, apperror.BadRequest("INVALID_ID", fmt.Sprintf("参数 %s 不合法", key), err))
		return 0, false
	}
	return uint(parsed), true
}

func requestOrigin(c *gin.Context) string {
	origin := strings.TrimSpace(c.GetHeader("Origin"))
	if origin != "" {
		return origin
	}
	scheme := strings.TrimSpace(c.GetHeader("X-Forwarded-Proto"))
	if scheme == "" {
		if c.Request.TLS != nil {
			scheme = "https"
		} else {
			scheme = "http"
		}
	}
	return fmt.Sprintf("%s://%s", scheme, c.Request.Host)
}

func asString(value any) string {
	text, _ := value.(string)
	return strings.TrimSpace(text)
}

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

func (h *StorageTargetHandler) ToggleStar(c *gin.Context) {
	id, ok := parseUintParam(c, "id")
	if !ok {
		return
	}
	item, err := h.service.ToggleStar(c.Request.Context(), id)
	if err != nil {
		response.Error(c, err)
		return
	}
	response.Success(c, item)
}

func (h *StorageTargetHandler) GetUsage(c *gin.Context) {
	id, ok := parseUintParam(c, "id")
	if !ok {
		return
	}
	usage, err := h.service.GetUsage(c.Request.Context(), id)
	if err != nil {
		response.Error(c, err)
		return
	}
	response.Success(c, usage)
}
