package provider

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"

	"github.com/1Panel-dev/1Panel/agent/buserr"
)

type VerifyRequest struct {
	Method  string
	URL     string
	Headers map[string]string
	Body    []byte
}

type verifyErrorResponse struct {
	Error struct {
		Message string `json:"message"`
	} `json:"error"`
	Message string `json:"message"`
}

const defaultVerifyTimeout = 30 * time.Second

func SkipVerification(provider string) bool {
	switch provider {
	case "vllm", "ollama", "kimi-coding":
		return true
	default:
		return false
	}
}

func VerifyAccount(provider, apiType, authMode, baseURL, apiKey, model string) error {
	req := BuildVerifyRequest(provider, apiType, authMode, baseURL, apiKey, model)
	httpReq, err := http.NewRequest(req.Method, req.URL, bytes.NewReader(req.Body))
	if err != nil {
		return err
	}
	for key, value := range req.Headers {
		httpReq.Header.Set(key, value)
	}
	httpReq.Header.Set("Accept", "application/json")
	resp, err := (&http.Client{Timeout: defaultVerifyTimeout}).Do(httpReq)
	if err != nil {
		return buserr.WithErr("ErrAgentAccountUnavailable", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
		body, readErr := io.ReadAll(io.LimitReader(resp.Body, 1024*1024))
		if readErr != nil {
			return buserr.WithErr("ErrAgentAccountUnavailable", readErr)
		}
		return buserr.WithErr("ErrAgentAccountUnavailable", errors.New(verifyHTTPError(resp.StatusCode, body)))
	}
	return nil
}

func BuildVerifyRequest(provider, apiType, authMode, baseURL, apiKey, model string) VerifyRequest {
	baseURL = strings.TrimSpace(baseURL)
	if provider != "custom" || !IsImageAPIType(apiType) {
		baseURL = strings.TrimRight(baseURL, "/")
	}
	headers := map[string]string{"Content-Type": "application/json"}
	request := VerifyRequest{Method: http.MethodPost, Headers: headers}

	if provider == "gemini" {
		request.URL = baseURL + "/v1beta/models/" + strings.TrimSpace(model) + ":generateContent"
		headers["x-goog-api-key"] = apiKey
		request.Body = mustJSON(map[string]interface{}{
			"contents": []map[string]interface{}{{"parts": []map[string]string{{"text": "test"}}}},
		})
		return request
	}

	switch apiType {
	case "openai-images":
		request.URL = imageVerifyURL(provider, baseURL, "/images/generations")
		headers["Authorization"] = "Bearer " + apiKey
		request.Body = mustJSON(map[string]interface{}{"model": model, "prompt": "test", "n": 1, "response_format": "url"})
	case "dashscope-images":
		request.URL = imageVerifyURL(provider, baseURL, "/api/v1/services/aigc/multimodal-generation/generation")
		headers["Authorization"] = "Bearer " + apiKey
		request.Body = mustJSON(map[string]interface{}{
			"model": model,
			"input": map[string]interface{}{"messages": []map[string]interface{}{
				{"role": "user", "content": []map[string]string{{"text": "test"}}},
			}},
			"parameters": map[string]interface{}{"n": 1},
		})
	case "minimax-images":
		request.URL = imageVerifyURL(provider, baseURL, "/v1/image_generation")
		headers["Authorization"] = "Bearer " + apiKey
		request.Body = mustJSON(map[string]interface{}{"model": model, "prompt": "test", "n": 1, "response_format": "url"})
	case "openrouter-images":
		request.URL = imageVerifyURL(provider, baseURL, "/api/v1/images")
		headers["Authorization"] = "Bearer " + apiKey
		request.Body = mustJSON(map[string]interface{}{"model": model, "prompt": "test", "n": 1, "response_format": "url"})
	case "anthropic-messages":
		request.URL = baseURL + "/v1/messages"
		if authMode == AuthModeBearer {
			headers["Authorization"] = "Bearer " + apiKey
		} else {
			headers["x-api-key"] = apiKey
		}
		headers["anthropic-version"] = "2023-06-01"
		request.Body = mustJSON(map[string]interface{}{
			"model": model, "max_tokens": 1, "stream": false,
			"messages": []map[string]interface{}{{"role": "user", "content": []map[string]string{{"type": "text", "text": "test"}}}},
		})
	case "openai-responses":
		request.URL = baseURL + "/responses"
		headers["Authorization"] = "Bearer " + apiKey
		request.Body = mustJSON(map[string]interface{}{"model": model, "input": "test", "max_output_tokens": 1, "stream": false})
	default:
		request.URL = baseURL + "/chat/completions"
		if provider != "ollama" || strings.TrimSpace(apiKey) != "" {
			headers["Authorization"] = "Bearer " + apiKey
		}
		request.Body = mustJSON(map[string]interface{}{
			"model": model, "messages": []map[string]string{{"role": "user", "content": "test"}}, "max_tokens": 1, "stream": false,
		})
	}
	return request
}

func imageVerifyURL(provider, baseURL, endpoint string) string {
	if provider == "custom" || strings.HasSuffix(strings.ToLower(baseURL), endpoint) {
		return baseURL
	}
	return baseURL + endpoint
}

func verifyHTTPError(statusCode int, body []byte) string {
	message := strings.TrimSpace(string(body))
	var payload verifyErrorResponse
	if err := json.Unmarshal(body, &payload); err == nil {
		if value := strings.TrimSpace(payload.Error.Message); value != "" {
			message = value
		} else if value := strings.TrimSpace(payload.Message); value != "" {
			message = value
		}
	}
	if message == "" {
		return fmt.Sprintf("validation request returned status %d", statusCode)
	}
	return message
}

func mustJSON(value interface{}) []byte {
	payload, err := json.Marshal(value)
	if err != nil {
		return []byte("{}")
	}
	return payload
}
