package collector

import (
	"encoding/xml"
	"log"
	"os"
	"os/exec"
	"strings"
)

type CronJob struct {
	Source      string `json:"source"`       // "system" oder "opnsense"
	Enabled    bool   `json:"enabled"`
	Minutes    string `json:"minutes"`
	Hours      string `json:"hours"`
	Days       string `json:"days"`
	Months     string `json:"months"`
	Weekdays   string `json:"weekdays"`
	Command    string `json:"command"`
	Parameters string `json:"parameters,omitempty"`
	Who        string `json:"who,omitempty"`
	Description string `json:"description,omitempty"`
	UUID       string `json:"uuid,omitempty"`
	Origin     string `json:"origin,omitempty"`
	Schedule   string `json:"schedule"`     // Menschenlesbar: "*/4 * * * *"
}

func CollectCron() []CronJob {
	var jobs []CronJob

	// 1. System-Crontab (crontab -l)
	sysJobs := collectSystemCrontab()
	jobs = append(jobs, sysJobs...)

	// 2. OPNsense config.xml Cron-Jobs
	opnJobs := collectOPNsenseCron()
	jobs = append(jobs, opnJobs...)

	log.Printf("Cron: %d Jobs gesammelt (%d System, %d OPNsense)",
		len(jobs), len(sysJobs), len(opnJobs))

	return jobs
}

func collectSystemCrontab() []CronJob {
	out, err := exec.Command("/bin/sh", "-c", "/usr/bin/crontab -l").Output()
	output := string(out)
	if err != nil {
		return nil
	}

	var jobs []CronJob
	for _, line := range strings.Split(output, "\n") {
		line = strings.TrimSpace(line)
		// Kommentare, leere Zeilen, Variablen ueberspringen
		if line == "" || strings.HasPrefix(line, "#") || strings.Contains(line, "=") {
			continue
		}

		// Crontab-Format: min hour day month weekday command
		fields := strings.Fields(line)
		if len(fields) < 6 {
			continue
		}

		command := strings.Join(fields[5:], " ")
		// Klammern und Redirects bereinigen
		command = strings.TrimPrefix(command, "(")
		command = strings.TrimSuffix(command, ") > /dev/null")

		jobs = append(jobs, CronJob{
			Source:   "system",
			Enabled:  true,
			Minutes:  fields[0],
			Hours:    fields[1],
			Days:     fields[2],
			Months:   fields[3],
			Weekdays: fields[4],
			Command:  command,
			Schedule: strings.Join(fields[:5], " "),
		})
	}

	return jobs
}

func collectOPNsenseCron() []CronJob {
	data, err := os.ReadFile("/conf/config.xml")
	if err != nil {
		return nil
	}

	type cronJob struct {
		UUID        string `xml:"uuid,attr"`
		Origin      string `xml:"origin"`
		Enabled     string `xml:"enabled"`
		Minutes     string `xml:"minutes"`
		Hours       string `xml:"hours"`
		Days        string `xml:"days"`
		Months      string `xml:"months"`
		Weekdays    string `xml:"weekdays"`
		Who         string `xml:"who"`
		Command     string `xml:"command"`
		Parameters  string `xml:"parameters"`
		Description string `xml:"description"`
	}

	type opnsenseCron struct {
		Jobs []cronJob `xml:"OPNsense>cron>jobs>job"`
	}

	var cfg opnsenseCron
	if err := xml.Unmarshal(data, &cfg); err != nil {
		log.Printf("Cron XML parsen fehlgeschlagen: %v", err)
		return nil
	}

	var jobs []CronJob
	for _, j := range cfg.Jobs {
		schedule := strings.Join([]string{j.Minutes, j.Hours, j.Days, j.Months, j.Weekdays}, " ")

		cmd := j.Command
		if j.Parameters != "" {
			cmd += " " + j.Parameters
		}

		jobs = append(jobs, CronJob{
			Source:      "opnsense",
			Enabled:     j.Enabled == "1",
			Minutes:     j.Minutes,
			Hours:       j.Hours,
			Days:        j.Days,
			Months:      j.Months,
			Weekdays:    j.Weekdays,
			Command:     cmd,
			Who:         j.Who,
			Description: strings.TrimSpace(j.Description),
			UUID:        j.UUID,
			Origin:      j.Origin,
			Schedule:    schedule,
		})
	}

	return jobs
}
