package context

import (
	"fmt"
	"strings"
	"time"

	"github.com/rcourtman/pulse-go-rewrite/internal/models"
)

// FormatResourceContext formats a single resource's context for AI consumption
func FormatResourceContext(ctx ResourceContext) string {
	var sb strings.Builder

	// Header with resource identity
	typeLabel := formatResourceType(ctx.ResourceType)
	sb.WriteString(fmt.Sprintf("### %s: %s", typeLabel, ctx.ResourceName))
	if ctx.Node != "" && ctx.ResourceType != "node" {
		sb.WriteString(fmt.Sprintf(" (on %s)", ctx.Node))
	}
	sb.WriteString("\n")

	// Current state
	sb.WriteString(fmt.Sprintf("**Status**: %s", ctx.Status))
	if ctx.Uptime > 0 {
		sb.WriteString(fmt.Sprintf(" | **Uptime**: %s", formatDuration(ctx.Uptime)))
	}
	sb.WriteString("\n")

	// Current metrics
	var metrics []string
	if ctx.CurrentCPU >= 0 {
		metrics = append(metrics, fmt.Sprintf("CPU: %.1f%%", ctx.CurrentCPU))
	}
	if ctx.CurrentMemory >= 0 {
		metrics = append(metrics, fmt.Sprintf("Memory: %.1f%%", ctx.CurrentMemory))
	}
	if ctx.CurrentDisk >= 0 {
		metrics = append(metrics, fmt.Sprintf("Disk: %.1f%%", ctx.CurrentDisk))
	}
	if len(metrics) > 0 {
		sb.WriteString("**Current**: " + strings.Join(metrics, " | ") + "\n")
	}

	// Trends section (the differentiating context)
	if len(ctx.Trends) > 0 {
		var trendLines []string
		for metric, trend := range ctx.Trends {
			if trend.DataPoints < 3 {
				continue // Skip if not enough data
			}
			line := formatTrendLine(metric, trend)
			if line != "" {
				trendLines = append(trendLines, line)
			}
		}
		if len(trendLines) > 0 {
			sb.WriteString("**Trends**: ")
			sb.WriteString(strings.Join(trendLines, " | "))
			sb.WriteString("\n")
		}
	}

	// Anomalies (high value - what's unusual)
	if len(ctx.Anomalies) > 0 {
		sb.WriteString("**ANOMALIES**: ")
		var anomalyDescs []string
		for _, a := range ctx.Anomalies {
			anomalyDescs = append(anomalyDescs, a.Description)
		}
		sb.WriteString(strings.Join(anomalyDescs, "; "))
		sb.WriteString("\n")
	}

	// Predictions (proactive value)
	if len(ctx.Predictions) > 0 {
		sb.WriteString("**Predictions**: ")
		var predDescs []string
		for _, p := range ctx.Predictions {
			predDescs = append(predDescs, fmt.Sprintf("%s in ~%.0f days", p.Event, p.DaysUntil))
		}
		sb.WriteString(strings.Join(predDescs, "; "))
		sb.WriteString("\n")
	}

	// User notes (context that only Pulse knows)
	if len(ctx.UserNotes) > 0 {
		sb.WriteString("**User Notes**: ")
		sb.WriteString(strings.Join(ctx.UserNotes, "; "))
		sb.WriteString("\n")
	}

	// Past issues (operational memory)
	if len(ctx.PastIssues) > 0 || ctx.LastRemediation != "" {
		sb.WriteString("**History**: ")
		if ctx.LastRemediation != "" {
			sb.WriteString(ctx.LastRemediation)
		}
		if len(ctx.PastIssues) > 0 {
			sb.WriteString(" Past issues: " + strings.Join(ctx.PastIssues, "; "))
		}
		sb.WriteString("\n")
	}

	return sb.String()
}

// formatTrendLine creates a compact trend description
func formatTrendLine(metric string, trend Trend) string {
	if trend.DataPoints < 3 {
		return ""
	}

	metricLabel := strings.Title(metric)
	
	// Direction with rate
	var directionStr string
	switch trend.Direction {
	case TrendGrowing:
		rate := formatRate(trend.RatePerDay)
		directionStr = fmt.Sprintf("(rising %s)", rate)
	case TrendDeclining:
		rate := formatRate(-trend.RatePerDay) // Make positive for display
		directionStr = fmt.Sprintf("(falling %s)", rate)
	case TrendVolatile:
		directionStr = "(volatile)"
	case TrendStable:
		directionStr = "(stable)"
	default:
		return ""
	}

	// Include range if interesting
	rangeStr := ""
	if trend.Max-trend.Min > 5 { // Only show range if variation is significant
		rangeStr = fmt.Sprintf(" (%.0f-%.0f%%)", trend.Min, trend.Max)
	}

	return fmt.Sprintf("%s: %s%s", metricLabel, directionStr, rangeStr)
}

// formatRate formats a rate value appropriately
func formatRate(ratePerDay float64) string {
	absRate := ratePerDay
	if absRate < 0 {
		absRate = -absRate
	}

	if absRate >= 1 {
		return fmt.Sprintf("%.1f/day", absRate)
	}
	// Convert to per hour if < 1/day
	ratePerHour := absRate / 24
	if ratePerHour >= 0.1 {
		return fmt.Sprintf("%.1f/hr", ratePerHour)
	}
	return "slow"
}

// FormatInfrastructureContext formats full infrastructure context for AI
func FormatInfrastructureContext(ctx *InfrastructureContext) string {
	var sb strings.Builder

	sb.WriteString("# Infrastructure State with Historical Context\n\n")
	sb.WriteString(fmt.Sprintf("*Generated at %s | Monitoring %d resources*\n\n",
		ctx.GeneratedAt.Format("2006-01-02 15:04"),
		ctx.TotalResources))

	// Global anomalies first (high priority)
	if len(ctx.Anomalies) > 0 {
		sb.WriteString("## Current Anomalies\n")
		for _, a := range ctx.Anomalies {
			sb.WriteString(fmt.Sprintf("- **%s**: %s\n", a.Metric, a.Description))
		}
		sb.WriteString("\n")
	}

	// Predictions (proactive insights)
	if len(ctx.Predictions) > 0 {
		sb.WriteString("## Predictions\n")
		for _, p := range ctx.Predictions {
			sb.WriteString(fmt.Sprintf("- **%s** on %s: %s (%.0f days, %.0f%% confidence)\n",
				p.Event, p.ResourceID, p.Basis, p.DaysUntil, p.Confidence*100))
		}
		sb.WriteString("\n")
	}

	// Recent changes (what's different)
	if len(ctx.Changes) > 0 {
		sb.WriteString("## Recent Changes\n")
		for _, c := range ctx.Changes {
			sb.WriteString(fmt.Sprintf("- %s: %s\n", c.ResourceName, c.Description))
		}
		sb.WriteString("\n")
	}

	// Resources by type
	if len(ctx.Nodes) > 0 {
		sb.WriteString("## Proxmox Nodes\n")
		for _, r := range ctx.Nodes {
			sb.WriteString(FormatResourceContext(r))
			sb.WriteString("\n")
		}
	}

	if len(ctx.VMs) > 0 {
		sb.WriteString("## Virtual Machines\n")
		for _, r := range ctx.VMs {
			sb.WriteString(FormatResourceContext(r))
		}
		sb.WriteString("\n")
	}

	if len(ctx.Containers) > 0 {
		sb.WriteString("## LXC/OCI Containers\n")
		for _, r := range ctx.Containers {
			sb.WriteString(FormatResourceContext(r))
		}
		sb.WriteString("\n")
	}

	if len(ctx.Storage) > 0 {
		sb.WriteString("## Storage\n")
		for _, r := range ctx.Storage {
			sb.WriteString(FormatResourceContext(r))
		}
		sb.WriteString("\n")
	}

	if len(ctx.DockerHosts) > 0 {
		sb.WriteString("## Docker Hosts\n")
		for _, r := range ctx.DockerHosts {
			sb.WriteString(FormatResourceContext(r))
		}
		sb.WriteString("\n")
	}

	if len(ctx.Hosts) > 0 {
		sb.WriteString("## Agent Hosts\n")
		for _, r := range ctx.Hosts {
			sb.WriteString(FormatResourceContext(r))
		}
		sb.WriteString("\n")
	}

	return sb.String()
}

// FormatCompactSummary creates a brief overview suitable for context-limited prompts
func FormatCompactSummary(ctx *InfrastructureContext) string {
	var sb strings.Builder

	sb.WriteString(fmt.Sprintf("Infrastructure: %d resources\n", ctx.TotalResources))

	// Count by status
	var healthy, warning, critical int
	countResource := func(resources []ResourceContext) {
		for _, r := range resources {
			switch {
			case len(r.Anomalies) > 0:
				critical++
			case hasGrowingTrend(r):
				warning++
			default:
				healthy++
			}
		}
	}
	countResource(ctx.Nodes)
	countResource(ctx.VMs)
	countResource(ctx.Containers)
	countResource(ctx.Storage)
	countResource(ctx.DockerHosts)
	countResource(ctx.Hosts)

	sb.WriteString(fmt.Sprintf("Health: %d healthy, %d warning, %d critical\n", healthy, warning, critical))

	if len(ctx.Anomalies) > 0 {
		sb.WriteString(fmt.Sprintf("Anomalies: %d active\n", len(ctx.Anomalies)))
	}

	if len(ctx.Predictions) > 0 {
		// Show most urgent prediction
		earliest := ctx.Predictions[0]
		for _, p := range ctx.Predictions[1:] {
			if p.DaysUntil < earliest.DaysUntil {
				earliest = p
			}
		}
		sb.WriteString(fmt.Sprintf("Nearest prediction: %s in %.0f days\n", earliest.Event, earliest.DaysUntil))
	}

	return sb.String()
}

// hasGrowingTrend checks if any metric trend is concerning
func hasGrowingTrend(r ResourceContext) bool {
	for _, t := range r.Trends {
		if t.Direction == TrendGrowing && t.RatePerDay > 1 {
			return true
		}
	}
	return false
}

// formatResourceType converts internal type to display label
func formatResourceType(t string) string {
	switch t {
	case "node":
		return "Node"
	case "vm":
		return "VM"
	case "container":
		return "Container"
	case "oci_container":
		return "OCI Container"
	case "storage":
		return "Storage"
	case "docker_host":
		return "Docker Host"
	case "docker_container":
		return "Docker Container"
	case "host":
		return "Host"
	default:
		return strings.Title(t)
	}
}

// formatDuration formats a duration in human-readable form
func formatDuration(d time.Duration) string {
	if d < time.Minute {
		return fmt.Sprintf("%ds", int(d.Seconds()))
	}
	if d < time.Hour {
		return fmt.Sprintf("%dm", int(d.Minutes()))
	}
	if d < 24*time.Hour {
		hours := int(d.Hours())
		mins := int(d.Minutes()) % 60
		if mins > 0 {
			return fmt.Sprintf("%dh%dm", hours, mins)
		}
		return fmt.Sprintf("%dh", hours)
	}
	days := int(d.Hours() / 24)
	hours := int(d.Hours()) % 24
	if hours > 0 {
		return fmt.Sprintf("%dd%dh", days, hours)
	}
	return fmt.Sprintf("%dd", days)
}

// FormatBackupStatus creates a human-readable backup status
func FormatBackupStatus(lastBackup time.Time) string {
	if lastBackup.IsZero() {
		return "never"
	}
	age := time.Since(lastBackup)
	if age < 24*time.Hour {
		return fmt.Sprintf("%.0fh ago", age.Hours())
	}
	days := age.Hours() / 24
	return fmt.Sprintf("%.0fd ago", days)
}

// FormatNodeForContext creates context for a Proxmox node
func FormatNodeForContext(node models.Node, trends map[string]Trend) ResourceContext {
	// Calculate memory percentage
	memPct := 0.0
	if node.Memory.Total > 0 {
		memPct = float64(node.Memory.Used) / float64(node.Memory.Total) * 100
	}

	ctx := ResourceContext{
		ResourceID:    node.ID,
		ResourceType:  "node",
		ResourceName:  node.Name,
		CurrentCPU:    node.CPU * 100, // Convert from 0-1 to percentage
		CurrentMemory: memPct,
		Status:        node.Status,
		Uptime:        time.Duration(node.Uptime) * time.Second,
		Trends:        trends,
	}

	return ctx
}

// FormatGuestForContext creates context for a VM or container
// Note: cpu is 0-1 ratio from Proxmox API, memUsage and diskUsage are already 0-100 percentages
func FormatGuestForContext(
	id, name, node, guestType, status string,
	cpu, memUsage, diskUsage float64,
	uptime int64,
	lastBackup time.Time,
	trends map[string]Trend,
) ResourceContext {
	ctx := ResourceContext{
		ResourceID:    id,
		ResourceType:  guestType,
		ResourceName:  name,
		Node:          node,
		CurrentCPU:    cpu * 100,  // Convert from 0-1 to percentage
		CurrentMemory: memUsage,   // Already 0-100 percentage from Memory.Usage
		CurrentDisk:   diskUsage,  // Already 0-100 percentage from Disk.Usage
		Status:        status,
		Uptime:        time.Duration(uptime) * time.Second,
		Trends:        trends,
	}

	return ctx
}

// FormatStorageForContext creates context for storage
func FormatStorageForContext(storage models.Storage, trends map[string]Trend) ResourceContext {
	usagePct := storage.Usage
	if usagePct == 0 && storage.Total > 0 {
		usagePct = float64(storage.Used) / float64(storage.Total) * 100
	}

	ctx := ResourceContext{
		ResourceID:   storage.ID,
		ResourceType: "storage",
		ResourceName: storage.Name,
		Node:         storage.Node,
		CurrentDisk:  usagePct,
		Status:       storage.Status,
		Trends:       trends,
	}

	return ctx
}
