package ai

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"time"
)

// AIEngine é o motor de inteligência artificial do OPHION
type AIEngine struct {
	apiKey    string
	model     string
	baseURL   string
	client    *http.Client
	enabled   bool
}

// Config configuração do AI Engine
type Config struct {
	APIKey  string
	Model   string
	Enabled bool
}

// AnomalyResult resultado da detecção de anomalias
type AnomalyResult struct {
	IsAnomaly   bool    `json:"is_anomaly"`
	Confidence  float64 `json:"confidence"`
	Severity    string  `json:"severity"`
	Description string  `json:"description"`
	Suggestions []string `json:"suggestions"`
	RelatedEvents []string `json:"related_events"`
}

// LogAnalysisResult resultado da análise de logs
type LogAnalysisResult struct {
	Clusters    []LogCluster `json:"clusters"`
	RootCause   string       `json:"root_cause"`
	Suggestions []string     `json:"suggestions"`
}

// LogCluster agrupamento de logs similares
type LogCluster struct {
	Pattern     string   `json:"pattern"`
	Count       int      `json:"count"`
	Severity    string   `json:"severity"`
	Examples    []string `json:"examples"`
	Description string   `json:"description"`
}

// PredictionResult resultado de previsões
type PredictionResult struct {
	Metric      string    `json:"metric"`
	CurrentValue float64  `json:"current_value"`
	PredictedValue float64 `json:"predicted_value"`
	TimeToThreshold string `json:"time_to_threshold"`
	Confidence  float64   `json:"confidence"`
	Recommendation string `json:"recommendation"`
}

// NewAIEngine cria nova instância do AI Engine
func NewAIEngine(config Config) *AIEngine {
	return &AIEngine{
		apiKey:  config.APIKey,
		model:   config.Model,
		baseURL: "https://api.openai.com/v1",
		client: &http.Client{
			Timeout: 30 * time.Second,
		},
		enabled: config.Enabled,
	}
}

// NewFromEnv cria AI Engine a partir de variáveis de ambiente
func NewFromEnv() *AIEngine {
	return NewAIEngine(Config{
		APIKey:  os.Getenv("OPENAI_API_KEY"),
		Model:   getEnvOrDefault("AI_MODEL", "gpt-4o-mini"),
		Enabled: os.Getenv("AI_ENABLED") == "true",
	})
}

func getEnvOrDefault(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}

// DetectAnomaly detecta anomalias em métricas
func (e *AIEngine) DetectAnomaly(ctx context.Context, metrics MetricsData) (*AnomalyResult, error) {
	if !e.enabled {
		return nil, fmt.Errorf("AI engine is disabled")
	}

	prompt := fmt.Sprintf(`Analise as seguintes métricas de servidor e detecte anomalias:

Host: %s
Período: últimas %d horas
Métricas atuais:
- CPU: %.2f%% (baseline: %.2f%%)
- Memória: %.2f%% (baseline: %.2f%%)
- Disco: %.2f%% (baseline: %.2f%%)
- Conexões de rede: %d (baseline: %d)

Histórico recente (últimas 24h):
%s

Responda em JSON com o formato:
{
  "is_anomaly": boolean,
  "confidence": 0.0-1.0,
  "severity": "low|medium|high|critical",
  "description": "descrição da anomalia",
  "suggestions": ["sugestão 1", "sugestão 2"],
  "related_events": ["evento relacionado 1"]
}`,
		metrics.Hostname,
		metrics.PeriodHours,
		metrics.CPU.Current, metrics.CPU.Baseline,
		metrics.Memory.Current, metrics.Memory.Baseline,
		metrics.Disk.Current, metrics.Disk.Baseline,
		metrics.Network.Connections, metrics.Network.BaselineConnections,
		metrics.History,
	)

	response, err := e.chat(ctx, prompt)
	if err != nil {
		return nil, err
	}

	var result AnomalyResult
	if err := json.Unmarshal([]byte(response), &result); err != nil {
		return nil, fmt.Errorf("failed to parse AI response: %w", err)
	}

	return &result, nil
}

// AnalyzeLogs analisa logs e identifica padrões
func (e *AIEngine) AnalyzeLogs(ctx context.Context, logs []LogEntry) (*LogAnalysisResult, error) {
	if !e.enabled {
		return nil, fmt.Errorf("AI engine is disabled")
	}

	// Preparar logs para análise
	logText := ""
	for i, log := range logs {
		if i >= 100 { // Limitar a 100 logs
			break
		}
		logText += fmt.Sprintf("[%s] %s: %s\n", log.Timestamp, log.Level, log.Message)
	}

	prompt := fmt.Sprintf(`Analise os seguintes logs de aplicação e identifique padrões, erros e possíveis causas raiz:

Logs:
%s

Responda em JSON com o formato:
{
  "clusters": [
    {
      "pattern": "padrão identificado",
      "count": 10,
      "severity": "error|warning|info",
      "examples": ["exemplo 1", "exemplo 2"],
      "description": "descrição do cluster"
    }
  ],
  "root_cause": "possível causa raiz dos problemas",
  "suggestions": ["sugestão de correção 1", "sugestão 2"]
}`, logText)

	response, err := e.chat(ctx, prompt)
	if err != nil {
		return nil, err
	}

	var result LogAnalysisResult
	if err := json.Unmarshal([]byte(response), &result); err != nil {
		return nil, fmt.Errorf("failed to parse AI response: %w", err)
	}

	return &result, nil
}

// PredictCapacity prevê capacidade futura
func (e *AIEngine) PredictCapacity(ctx context.Context, data CapacityData) (*PredictionResult, error) {
	if !e.enabled {
		return nil, fmt.Errorf("AI engine is disabled")
	}

	prompt := fmt.Sprintf(`Analise os dados históricos e preveja quando o recurso atingirá o limite:

Recurso: %s
Valor atual: %.2f%%
Limite crítico: %.2f%%
Dados históricos (últimos 30 dias):
%s

Responda em JSON com o formato:
{
  "metric": "nome da métrica",
  "current_value": 75.5,
  "predicted_value": 95.0,
  "time_to_threshold": "em 7 dias",
  "confidence": 0.85,
  "recommendation": "recomendação de ação"
}`, data.Metric, data.CurrentValue, data.Threshold, data.History)

	response, err := e.chat(ctx, prompt)
	if err != nil {
		return nil, err
	}

	var result PredictionResult
	if err := json.Unmarshal([]byte(response), &result); err != nil {
		return nil, fmt.Errorf("failed to parse AI response: %w", err)
	}

	return &result, nil
}

// chat envia mensagem para a API da OpenAI
func (e *AIEngine) chat(ctx context.Context, prompt string) (string, error) {
	requestBody := map[string]interface{}{
		"model": e.model,
		"messages": []map[string]string{
			{
				"role":    "system",
				"content": "Você é um especialista em observabilidade e monitoramento de infraestrutura. Analise os dados fornecidos e forneça insights acionáveis. Sempre responda em JSON válido.",
			},
			{
				"role":    "user",
				"content": prompt,
			},
		},
		"temperature": 0.3,
		"max_tokens":  2000,
	}

	jsonBody, err := json.Marshal(requestBody)
	if err != nil {
		return "", err
	}

	req, err := http.NewRequestWithContext(ctx, "POST", e.baseURL+"/chat/completions", bytes.NewBuffer(jsonBody))
	if err != nil {
		return "", err
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+e.apiKey)

	resp, err := e.client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	var result struct {
		Choices []struct {
			Message struct {
				Content string `json:"content"`
			} `json:"message"`
		} `json:"choices"`
		Error struct {
			Message string `json:"message"`
		} `json:"error"`
	}

	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return "", err
	}

	if result.Error.Message != "" {
		return "", fmt.Errorf("OpenAI error: %s", result.Error.Message)
	}

	if len(result.Choices) == 0 {
		return "", fmt.Errorf("no response from AI")
	}

	return result.Choices[0].Message.Content, nil
}

// IsEnabled verifica se o AI Engine está habilitado
func (e *AIEngine) IsEnabled() bool {
	return e.enabled
}

// === Tipos de dados auxiliares ===

// MetricsData dados de métricas para análise
type MetricsData struct {
	Hostname    string
	PeriodHours int
	CPU         MetricValue
	Memory      MetricValue
	Disk        MetricValue
	Network     NetworkMetric
	History     string
}

// MetricValue valor de métrica com baseline
type MetricValue struct {
	Current  float64
	Baseline float64
}

// NetworkMetric métricas de rede
type NetworkMetric struct {
	Connections         int
	BaselineConnections int
}

// LogEntry entrada de log
type LogEntry struct {
	Timestamp string
	Level     string
	Message   string
	Source    string
}

// CapacityData dados para previsão de capacidade
type CapacityData struct {
	Metric       string
	CurrentValue float64
	Threshold    float64
	History      string
}
