package stats

import (
	"database/sql"
	"log"
)

// CreateStatsTables creates the necessary tables for stats collection
func CreateStatsTables(db *sql.DB) error {
	// Time-series stats table
	_, err := db.Exec(`
		CREATE TABLE IF NOT EXISTS stats_timeseries (
			id INTEGER PRIMARY KEY AUTOINCREMENT,
			timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
			component TEXT NOT NULL,
			metric TEXT NOT NULL,
			value REAL NOT NULL,
			metadata TEXT,
			INDEX idx_component_metric_time (component, metric, timestamp)
		)
	`)
	if err != nil {
		return err
	}

	// Performance metrics table
	_, err = db.Exec(`
		CREATE TABLE IF NOT EXISTS performance_metrics (
			id INTEGER PRIMARY KEY AUTOINCREMENT,
			timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
			endpoint TEXT NOT NULL,
			method TEXT NOT NULL,
			response_time_ms REAL NOT NULL,
			status_code INTEGER NOT NULL,
			bytes_sent INTEGER DEFAULT 0,
			bytes_received INTEGER DEFAULT 0,
			user_agent TEXT,
			ip_address TEXT,
			INDEX idx_endpoint_time (endpoint, timestamp),
			INDEX idx_status_time (status_code, timestamp)
		)
	`)
	if err != nil {
		return err
	}

	// Bandwidth tracking table
	_, err = db.Exec(`
		CREATE TABLE IF NOT EXISTS bandwidth_stats (
			id INTEGER PRIMARY KEY AUTOINCREMENT,
			timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
			torrent_hash TEXT NOT NULL,
			bytes_served INTEGER NOT NULL,
			bytes_from_peers INTEGER DEFAULT 0,
			peer_count INTEGER DEFAULT 0,
			source TEXT NOT NULL, -- 'webseed', 'tracker', 'dht'
			INDEX idx_torrent_time (torrent_hash, timestamp),
			INDEX idx_source_time (source, timestamp)
		)
	`)
	if err != nil {
		return err
	}

	// System metrics table
	_, err = db.Exec(`
		CREATE TABLE IF NOT EXISTS system_metrics (
			id INTEGER PRIMARY KEY AUTOINCREMENT,
			timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
			cpu_percent REAL NOT NULL,
			memory_bytes INTEGER NOT NULL,
			goroutines INTEGER NOT NULL,
			heap_objects INTEGER NOT NULL,
			gc_cycles INTEGER NOT NULL,
			disk_usage INTEGER DEFAULT 0
		)
	`)
	if err != nil {
		return err
	}

	// Component health history
	_, err = db.Exec(`
		CREATE TABLE IF NOT EXISTS component_health (
			id INTEGER PRIMARY KEY AUTOINCREMENT,
			timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
			component TEXT NOT NULL,
			status TEXT NOT NULL, -- 'healthy', 'degraded', 'unhealthy'
			error_message TEXT,
			response_time_ms REAL,
			INDEX idx_component_status_time (component, status, timestamp)
		)
	`)

	return err
}

// StatsDB wraps database operations for stats
type StatsDB struct {
	db *sql.DB
}

// NewStatsDB creates a new stats database wrapper
func NewStatsDB(db *sql.DB) *StatsDB {
	return &StatsDB{db: db}
}

// RecordTimeSeries records a time-series data point
func (sdb *StatsDB) RecordTimeSeries(component, metric string, value float64, metadata string) error {
	_, err := sdb.db.Exec(`
		INSERT INTO stats_timeseries (component, metric, value, metadata)
		VALUES (?, ?, ?, ?)
	`, component, metric, value, metadata)
	return err
}

// RecordPerformance records a performance metric
func (sdb *StatsDB) RecordPerformance(endpoint, method string, responseTime float64, statusCode int, bytesSent, bytesReceived int64, userAgent, ipAddress string) error {
	_, err := sdb.db.Exec(`
		INSERT INTO performance_metrics (endpoint, method, response_time_ms, status_code, bytes_sent, bytes_received, user_agent, ip_address)
		VALUES (?, ?, ?, ?, ?, ?, ?, ?)
	`, endpoint, method, responseTime, statusCode, bytesSent, bytesReceived, userAgent, ipAddress)
	return err
}

// RecordBandwidth records bandwidth usage
func (sdb *StatsDB) RecordBandwidth(torrentHash string, bytesServed, bytesFromPeers int64, peerCount int, source string) error {
	_, err := sdb.db.Exec(`
		INSERT INTO bandwidth_stats (torrent_hash, bytes_served, bytes_from_peers, peer_count, source)
		VALUES (?, ?, ?, ?, ?)
	`, torrentHash, bytesServed, bytesFromPeers, peerCount, source)
	return err
}

// RecordSystemMetrics records system performance metrics
func (sdb *StatsDB) RecordSystemMetrics(cpuPercent float64, memoryBytes int64, goroutines, heapObjects, gcCycles int, diskUsage int64) error {
	_, err := sdb.db.Exec(`
		INSERT INTO system_metrics (cpu_percent, memory_bytes, goroutines, heap_objects, gc_cycles, disk_usage)
		VALUES (?, ?, ?, ?, ?, ?)
	`, cpuPercent, memoryBytes, goroutines, heapObjects, gcCycles, diskUsage)
	return err
}

// RecordComponentHealth records component health status
func (sdb *StatsDB) RecordComponentHealth(component, status, errorMessage string, responseTime float64) error {
	_, err := sdb.db.Exec(`
		INSERT INTO component_health (component, status, error_message, response_time_ms)
		VALUES (?, ?, ?, ?)
	`, component, status, errorMessage, responseTime)
	return err
}

// GetAverageResponseTime gets average response time for last N minutes
func (sdb *StatsDB) GetAverageResponseTime(minutes int) (float64, error) {
	var avg float64
	err := sdb.db.QueryRow(`
		SELECT COALESCE(AVG(response_time_ms), 0)
		FROM performance_metrics
		WHERE timestamp > datetime('now', '-' || ? || ' minutes')
	`, minutes).Scan(&avg)
	return avg, err
}

// GetRequestsPerSecond gets requests per second for last N minutes
func (sdb *StatsDB) GetRequestsPerSecond(minutes int) (float64, error) {
	var count int64
	err := sdb.db.QueryRow(`
		SELECT COUNT(*)
		FROM performance_metrics
		WHERE timestamp > datetime('now', '-' || ? || ' minutes')
	`, minutes).Scan(&count)
	
	if err != nil {
		return 0, err
	}
	
	return float64(count) / float64(minutes*60), nil
}

// GetErrorRate gets error rate percentage for last N minutes
func (sdb *StatsDB) GetErrorRate(minutes int) (float64, error) {
	var totalRequests, errorRequests int64
	
	err := sdb.db.QueryRow(`
		SELECT COUNT(*) FROM performance_metrics
		WHERE timestamp > datetime('now', '-' || ? || ' minutes')
	`, minutes).Scan(&totalRequests)
	if err != nil {
		return 0, err
	}
	
	err = sdb.db.QueryRow(`
		SELECT COUNT(*) FROM performance_metrics
		WHERE timestamp > datetime('now', '-' || ? || ' minutes')
		AND status_code >= 400
	`, minutes).Scan(&errorRequests)
	if err != nil {
		return 0, err
	}
	
	if totalRequests == 0 {
		return 0, nil
	}
	
	return float64(errorRequests) / float64(totalRequests) * 100, nil
}

// GetBandwidthStats gets bandwidth statistics for last N hours
func (sdb *StatsDB) GetBandwidthStats(hours int) (map[string]interface{}, error) {
	rows, err := sdb.db.Query(`
		SELECT 
			SUM(bytes_served) as total_served,
			SUM(bytes_from_peers) as total_from_peers,
			COUNT(DISTINCT torrent_hash) as active_torrents,
			AVG(peer_count) as avg_peer_count
		FROM bandwidth_stats
		WHERE timestamp > datetime('now', '-' || ? || ' hours')
	`, hours)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	
	var totalServed, totalFromPeers, activeTorrents, avgPeerCount int64
	if rows.Next() {
		err = rows.Scan(&totalServed, &totalFromPeers, &activeTorrents, &avgPeerCount)
		if err != nil {
			return nil, err
		}
	}
	
	var p2pOffload float64
	if totalServed > 0 {
		p2pOffload = float64(totalFromPeers) / float64(totalServed) * 100
	}
	
	return map[string]interface{}{
		"total_served":      totalServed,
		"total_from_peers":  totalFromPeers,
		"p2p_offload_percent": p2pOffload,
		"active_torrents":   activeTorrents,
		"avg_peer_count":    avgPeerCount,
	}, nil
}

// GetSystemHealthOverTime gets system health metrics over time
func (sdb *StatsDB) GetSystemHealthOverTime(hours int) ([]map[string]interface{}, error) {
	rows, err := sdb.db.Query(`
		SELECT 
			datetime(timestamp) as time,
			cpu_percent,
			memory_bytes,
			goroutines
		FROM system_metrics
		WHERE timestamp > datetime('now', '-' || ? || ' hours')
		ORDER BY timestamp DESC
		LIMIT 100
	`, hours)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	
	var results []map[string]interface{}
	for rows.Next() {
		var timestamp string
		var cpu float64
		var memory int64
		var goroutines int
		
		err = rows.Scan(&timestamp, &cpu, &memory, &goroutines)
		if err != nil {
			continue
		}
		
		results = append(results, map[string]interface{}{
			"timestamp":  timestamp,
			"cpu":        cpu,
			"memory":     memory,
			"goroutines": goroutines,
		})
	}
	
	return results, nil
}

// CleanupOldStats removes old statistics data
func (sdb *StatsDB) CleanupOldStats(daysToKeep int) error {
	tables := []string{
		"stats_timeseries",
		"performance_metrics", 
		"bandwidth_stats",
		"system_metrics",
		"component_health",
	}
	
	for _, table := range tables {
		_, err := sdb.db.Exec(`
			DELETE FROM `+table+`
			WHERE timestamp < datetime('now', '-' || ? || ' days')
		`, daysToKeep)
		if err != nil {
			log.Printf("Error cleaning up %s: %v", table, err)
		}
	}
	
	return nil
}

// GetTopTorrentsByBandwidth gets most popular torrents by bandwidth
func (sdb *StatsDB) GetTopTorrentsByBandwidth(hours int, limit int) ([]map[string]interface{}, error) {
	rows, err := sdb.db.Query(`
		SELECT 
			torrent_hash,
			SUM(bytes_served) as total_served,
			AVG(peer_count) as avg_peers,
			COUNT(*) as records
		FROM bandwidth_stats
		WHERE timestamp > datetime('now', '-' || ? || ' hours')
		GROUP BY torrent_hash
		ORDER BY total_served DESC
		LIMIT ?
	`, hours, limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	
	var results []map[string]interface{}
	for rows.Next() {
		var hash string
		var served int64
		var avgPeers float64
		var records int
		
		err = rows.Scan(&hash, &served, &avgPeers, &records)
		if err != nil {
			continue
		}
		
		results = append(results, map[string]interface{}{
			"hash":         hash,
			"bytes_served": served,
			"avg_peers":    avgPeers,
			"activity":     records,
		})
	}
	
	return results, nil
}