package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"time"

	"git.wntrmute.dev/mc/mcias/internal/db"
	"git.wntrmute.dev/mc/mcias/internal/model"
)

func (t *tool) runAudit(args []string) {
	if len(args) == 0 {
		fatalf("audit requires a subcommand: tail, query")
	}
	switch args[0] {
	case "tail":
		t.auditTail(args[1:])
	case "query":
		t.auditQuery(args[1:])
	default:
		fatalf("unknown audit subcommand %q", args[0])
	}
}

func (t *tool) auditTail(args []string) {
	fs := flag.NewFlagSet("audit tail", flag.ExitOnError)
	n := fs.Int("n", 50, "number of events to show")
	asJSON := fs.Bool("json", false, "output as newline-delimited JSON")
	_ = fs.Parse(args)

	if *n <= 0 {
		fatalf("audit tail: --n must be positive")
	}

	events, err := t.db.TailAuditEvents(*n)
	if err != nil {
		fatalf("tail audit events: %v", err)
	}

	printAuditEvents(events, *asJSON)
}

func (t *tool) auditQuery(args []string) {
	fs := flag.NewFlagSet("audit query", flag.ExitOnError)
	accountUUID := fs.String("account", "", "filter by account UUID (actor or target)")
	eventType := fs.String("type", "", "filter by event type")
	sinceStr := fs.String("since", "", "filter events on or after this RFC-3339 timestamp")
	asJSON := fs.Bool("json", false, "output as newline-delimited JSON")
	_ = fs.Parse(args)

	p := db.AuditQueryParams{
		EventType: *eventType,
	}

	if *accountUUID != "" {
		a, err := t.db.GetAccountByUUID(*accountUUID)
		if err != nil {
			fatalf("get account: %v", err)
		}
		p.AccountID = &a.ID
	}

	if *sinceStr != "" {
		since, err := time.Parse(time.RFC3339, *sinceStr)
		if err != nil {
			fatalf("audit query: --since must be an RFC-3339 timestamp (e.g. 2006-01-02T15:04:05Z): %v", err)
		}
		p.Since = &since
	}

	events, err := t.db.ListAuditEvents(p)
	if err != nil {
		fatalf("query audit events: %v", err)
	}

	printAuditEvents(events, *asJSON)
}

func printAuditEvents(events []*model.AuditEvent, asJSON bool) {
	if len(events) == 0 {
		fmt.Println("no audit events found")
		return
	}

	if asJSON {
		enc := json.NewEncoder(os.Stdout)
		for _, ev := range events {
			if err := enc.Encode(ev); err != nil {
				fatalf("encode audit event: %v", err)
			}
		}
		return
	}

	fmt.Printf("%-20s  %-22s  %-15s  %s\n", "TIME", "EVENT TYPE", "IP", "DETAILS")
	fmt.Println("────────────────────────────────────────────────────────────────────────────────")
	for _, ev := range events {
		ip := ev.IPAddress
		if ip == "" {
			ip = "-"
		}
		details := ev.Details
		if details == "" {
			details = "-"
		}
		fmt.Printf("%-20s  %-22s  %-15s  %s\n",
			ev.EventTime.Format("2006-01-02T15:04:05Z"),
			ev.EventType,
			ip,
			details,
		)
	}
}
