package elasticsearch

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

// Client 封装 Elasticsearch REST API 客户端
type Client struct {
	hosts    []string
	username string
	password string
	client   *http.Client
}

// NewClient 创建 ES 客户端
func NewClient(hosts []string, username, password string) *Client {
	return &Client{
		hosts:    hosts,
		username: username,
		password: password,
		client: &http.Client{
			Timeout: 30 * time.Second,
		},
	}
}

// LogEntry 异常日志条目
type LogEntry struct {
	Timestamp string `json:"@timestamp"`
	Level     string `json:"level"`
	Message   string `json:"message"`
	Host      string `json:"host"`
	Source    string `json:"source"`
}

// SearchResult 搜索结果
type SearchResult struct {
	Total int
	Logs  []LogEntry
	Raw   map[string]interface{}
}

// SearchAbnormalLogs 搜索异常日志
// indexPattern: 索引模式，如 "logstash-*"
// timeRange: 时间范围，如 "15m", "1h"
// minLevel: 最低日志级别，如 "ERROR"
func (c *Client) SearchAbnormalLogs(indexPattern, timeRange, minLevel string) (*SearchResult, error) {
	if indexPattern == "" {
		indexPattern = "logstash-*"
	}
	if timeRange == "" {
		timeRange = "15m"
	}
	if minLevel == "" {
		minLevel = "ERROR"
	}

	// 构建 ES 查询 DSL
	query := map[string]interface{}{
		"query": map[string]interface{}{
			"bool": map[string]interface{}{
				"must": []map[string]interface{}{
					{
						"range": map[string]interface{}{
							"@timestamp": map[string]interface{}{
								"gte": fmt.Sprintf("now-%s", timeRange),
								"lte": "now",
							},
						},
					},
					{
						"terms": map[string]interface{}{
							"level.keyword": c.getLevelTerms(minLevel),
						},
					},
				},
			},
		},
		"sort": []map[string]interface{}{
			{"@timestamp": map[string]string{"order": "desc"}},
		},
		"size": 100,
	}

	body, err := json.Marshal(query)
	if err != nil {
		return nil, fmt.Errorf("构建 ES 查询失败: %w", err)
	}

	url := fmt.Sprintf("%s/%s/_search", c.hosts[0], indexPattern)
	req, err := http.NewRequest("POST", url, bytes.NewReader(body))
	if err != nil {
		return nil, fmt.Errorf("创建请求失败: %w", err)
	}

	req.Header.Set("Content-Type", "application/json")
	if c.username != "" {
		req.SetBasicAuth(c.username, c.password)
	}

	resp, err := c.client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("ES 请求失败: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		respBody, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("ES 返回错误状态码 %d: %s", resp.StatusCode, string(respBody))
	}

	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取 ES 响应失败: %w", err)
	}

	var esResp map[string]interface{}
	if err := json.Unmarshal(respBody, &esResp); err != nil {
		return nil, fmt.Errorf("解析 ES 响应失败: %w", err)
	}

	result := &SearchResult{
		Raw: esResp,
	}

	// 解析 hits
	if hits, ok := esResp["hits"].(map[string]interface{}); ok {
		if total, ok := hits["total"].(map[string]interface{}); ok {
			if val, ok := total["value"].(float64); ok {
				result.Total = int(val)
			}
		}
		if hitList, ok := hits["hits"].([]interface{}); ok {
			for _, h := range hitList {
				hit, ok := h.(map[string]interface{})
				if !ok {
					continue
				}
				source, ok := hit["_source"].(map[string]interface{})
				if !ok {
					continue
				}

				entry := LogEntry{
					Timestamp: getString(source, "@timestamp"),
					Level:     getString(source, "level"),
					Message:   getString(source, "message"),
					Host:      getString(source, "host"),
					Source:    getString(source, "source"),
				}
				result.Logs = append(result.Logs, entry)
			}
		}
	}

	return result, nil
}

// getLevelTerms 根据最低级别返回所有不低于该级别的日志级别
// 级别从高到低: FATAL > ERROR > WARN > INFO > DEBUG > TRACE
// minLevel=ERROR -> 返回 [FATAL, ERROR]
func (c *Client) getLevelTerms(minLevel string) []string {
	levels := []string{"FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"}
	upper := strings.ToUpper(minLevel)
	for i, l := range levels {
		if l == upper {
			return levels[:i+1] // 返回该级别及更高级别
		}
	}
	// 默认返回 FATAL 和 ERROR
	return []string{"FATAL", "ERROR"}
}

// getString 安全获取 map 中的字符串值
func getString(m map[string]interface{}, key string) string {
	if v, ok := m[key]; ok {
		switch val := v.(type) {
		case string:
			return val
		case map[string]interface{}:
			if keyword, ok := val["keyword"]; ok {
				if s, ok := keyword.(string); ok {
					return s
				}
			}
			if s, ok := val["name"].(string); ok {
				return s
			}
		}
	}
	return ""
}

// Ping 检查 ES 连通性
func (c *Client) Ping() error {
	url := c.hosts[0]
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return err
	}
	if c.username != "" {
		req.SetBasicAuth(c.username, c.password)
	}

	resp, err := c.client.Do(req)
	if err != nil {
		return fmt.Errorf("ES 连接失败: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("ES 返回状态码 %d", resp.StatusCode)
	}
	return nil
}
