package collector

import (
	"encoding/json"
	"log"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

type PBSInfo struct {
	Available  bool            `json:"available"`
	Version    string          `json:"version,omitempty"`
	Datastores []PBSDatastore  `json:"datastores,omitempty"`
	Tasks      []PBSTask       `json:"tasks,omitempty"`
	GC         []PBSGCStatus   `json:"gc,omitempty"`
	SyncJobs   int             `json:"sync_jobs"`
}

type PBSDatastore struct {
	Name        string `json:"name"`
	Path        string `json:"path,omitempty"`
	Total       int64  `json:"total"`
	Used        int64  `json:"used"`
	Available   int64  `json:"available"`
	BackupCount int    `json:"backup_count"`
}

type PBSTask struct {
	ID        string `json:"id,omitempty"`
	Node      string `json:"node,omitempty"`
	Type      string `json:"type,omitempty"`
	Status    string `json:"status,omitempty"`
	StartTime int64  `json:"start_time,omitempty"`
	EndTime   int64  `json:"end_time,omitempty"`
	Duration  int64  `json:"duration,omitempty"`
	User      string `json:"user,omitempty"`
	Datastore string `json:"datastore,omitempty"`
	Running   bool   `json:"running,omitempty"`
}

type PBSGCStatus struct {
	Datastore string `json:"datastore"`
	Status    string `json:"status,omitempty"`
	LastRun   int64  `json:"last_run,omitempty"`
	Duration  int64  `json:"duration,omitempty"`
}

func CollectPBS() *PBSInfo {
	// PBS erkennen
	if _, err := os.Stat("/usr/sbin/proxmox-backup-manager"); err != nil {
		return nil // PBS nicht installiert
	}

	log.Printf("PBS: proxmox-backup-manager gefunden, sammle Daten...")
	pbs := &PBSInfo{Available: true}

	// Version
	if out, err := exec.Command("/usr/sbin/proxmox-backup-manager", "versions", "--output-format", "json").Output(); err == nil {
		var versions []map[string]interface{}
		if json.Unmarshal(out, &versions) == nil {
			for _, v := range versions {
				if pkg, ok := v["Package"].(string); ok && pkg == "proxmox-backup-server" {
					if ver, ok := v["Version"].(string); ok {
						pbs.Version = ver
					}
				}
			}
		}
	}

	// Datastores
	if out, err := exec.Command("/usr/sbin/proxmox-backup-manager", "datastore", "list", "--output-format", "json").Output(); err == nil {
		var list []map[string]interface{}
		if json.Unmarshal(out, &list) == nil {
			for _, d := range list {
				ds := PBSDatastore{}
				if name, ok := d["name"].(string); ok {
					ds.Name = name
				}
				if path, ok := d["path"].(string); ok {
					ds.Path = path
				}
				if total, ok := d["total"].(float64); ok {
					ds.Total = int64(total)
				}
				if used, ok := d["used"].(float64); ok {
					ds.Used = int64(used)
				}
				if avail, ok := d["avail"].(float64); ok {
					ds.Available = int64(avail)
				}
				// Disk-Auslastung via df
				if ds.Path != "" {
					dfCmd := exec.Command("/bin/df", "-B1", "--output=size,used,avail", ds.Path)
					if out, err := dfCmd.Output(); err == nil {
						lines := strings.Split(strings.TrimSpace(string(out)), "\n")
						if len(lines) >= 2 {
							fields := strings.Fields(lines[1])
							if len(fields) >= 3 {
								if v, err := strconv.ParseInt(fields[0], 10, 64); err == nil {
									ds.Total = v
								}
								if v, err := strconv.ParseInt(fields[1], 10, 64); err == nil {
									ds.Used = v
								}
								if v, err := strconv.ParseInt(fields[2], 10, 64); err == nil {
									ds.Available = v
								}
							}
						}
					}

					// Backup-Anzahl: alle Timestamp-Verzeichnisse zaehlen
					countCmd := exec.Command("/bin/sh", "-c",
						`find `+ds.Path+` -type d 2>/dev/null | grep -cE '/[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$'`)
					if out, err := countCmd.Output(); err == nil {
						if n, err := strconv.Atoi(strings.TrimSpace(string(out))); err == nil {
							ds.BackupCount = n
						}
					}
				}

				pbs.Datastores = append(pbs.Datastores, ds)
			}
		}
	} else {
		log.Printf("PBS: datastore list fehler: %v", err)
	}

	// Letzte Tasks (max 20)
	if out, err := exec.Command("/usr/sbin/proxmox-backup-manager", "task", "list", "--limit", "20", "--output-format", "json").Output(); err == nil {
		var list []map[string]interface{}
		if json.Unmarshal(out, &list) == nil {
			for _, t := range list {
				task := PBSTask{}
				if id, ok := t["upid"].(string); ok {
					task.ID = id
				}
				if node, ok := t["node"].(string); ok {
					task.Node = node
				}
				if typ, ok := t["type"].(string); ok {
					task.Type = typ
				}
				if status, ok := t["status"].(string); ok {
					task.Status = status
				}
				if start, ok := t["starttime"].(float64); ok {
					task.StartTime = int64(start)
				}
				if end, ok := t["endtime"].(float64); ok && end > 0 {
					task.EndTime = int64(end)
					if task.StartTime > 0 {
						task.Duration = task.EndTime - task.StartTime
					}
				} else {
					task.Running = true
					task.Status = "running"
				}
				if user, ok := t["user"].(string); ok {
					task.User = user
				}
				pbs.Tasks = append(pbs.Tasks, task)
			}
		}
	} else {
		log.Printf("PBS: task list fehler: %v", err)
	}

	// Garbage Collection Status pro Datastore
	for _, ds := range pbs.Datastores {
		gc := PBSGCStatus{Datastore: ds.Name}
		if out, err := exec.Command("/usr/sbin/proxmox-backup-manager", "garbage-collection", "status", ds.Name, "--output-format", "json").Output(); err == nil {
			var status map[string]interface{}
			if json.Unmarshal(out, &status) == nil {
				if upid, ok := status["upid"].(string); ok && upid != "" {
					gc.Status = "running"
				} else if lastRun, ok := status["last-run-starttime"].(float64); ok {
					gc.LastRun = int64(lastRun)
					if duration, ok := status["last-run-duration"].(float64); ok {
						gc.Duration = int64(duration)
					}
					gc.Status = "ok"
				} else {
					gc.Status = "never"
				}
			}
		}
		pbs.GC = append(pbs.GC, gc)
	}

	// Sync Jobs zählen
	if out, err := exec.Command("/usr/sbin/proxmox-backup-manager", "sync-job", "list", "--output-format", "json").Output(); err == nil {
		var jobs []interface{}
		if json.Unmarshal(out, &jobs) == nil {
			pbs.SyncJobs = len(jobs)
		}
	}

	log.Printf("PBS: %d Datastores, %d Tasks, %d SyncJobs gesammelt", len(pbs.Datastores), len(pbs.Tasks), pbs.SyncJobs)
	return pbs
}
