package main

import (
	"flag"
	"fmt"
	"os"
	"strings"
)

func (t *tool) runWebAuthn(args []string) {
	if len(args) == 0 {
		fatalf("webauthn requires a subcommand: list, delete, reset")
	}
	switch args[0] {
	case "list":
		t.webauthnList(args[1:])
	case "delete":
		t.webauthnDelete(args[1:])
	case "reset":
		t.webauthnReset(args[1:])
	default:
		fatalf("unknown webauthn subcommand %q", args[0])
	}
}

func (t *tool) webauthnList(args []string) {
	fs := flag.NewFlagSet("webauthn list", flag.ExitOnError)
	id := fs.String("id", "", "account UUID (required)")
	_ = fs.Parse(args)

	if *id == "" {
		fatalf("webauthn list: --id is required")
	}

	a, err := t.db.GetAccountByUUID(*id)
	if err != nil {
		fatalf("get account: %v", err)
	}

	creds, err := t.db.GetWebAuthnCredentials(a.ID)
	if err != nil {
		fatalf("list webauthn credentials: %v", err)
	}

	if len(creds) == 0 {
		fmt.Printf("No WebAuthn credentials for account %s\n", a.Username)
		return
	}

	fmt.Printf("WebAuthn credentials for %s:\n\n", a.Username)
	fmt.Printf("%-6s  %-20s  %-12s  %-8s  %-20s  %-20s\n",
		"ID", "NAME", "DISCOVERABLE", "COUNT", "CREATED", "LAST USED")
	fmt.Println(strings.Repeat("-", 96))
	for _, c := range creds {
		disc := "no"
		if c.Discoverable {
			disc = "yes"
		}
		lastUsed := "never"
		if c.LastUsedAt != nil {
			lastUsed = c.LastUsedAt.UTC().Format("2006-01-02 15:04:05")
		}
		fmt.Printf("%-6d  %-20s  %-12s  %-8d  %-20s  %-20s\n",
			c.ID, c.Name, disc, c.SignCount,
			c.CreatedAt.UTC().Format("2006-01-02 15:04:05"), lastUsed)
	}
}

func (t *tool) webauthnDelete(args []string) {
	fs := flag.NewFlagSet("webauthn delete", flag.ExitOnError)
	id := fs.String("id", "", "account UUID (required)")
	credID := fs.Int64("credential-id", 0, "credential DB row ID (required)")
	_ = fs.Parse(args)

	if *id == "" || *credID == 0 {
		fatalf("webauthn delete: --id and --credential-id are required")
	}

	a, err := t.db.GetAccountByUUID(*id)
	if err != nil {
		fatalf("get account: %v", err)
	}

	if err := t.db.DeleteWebAuthnCredential(*credID, a.ID); err != nil {
		fatalf("delete webauthn credential: %v", err)
	}

	if err := t.db.WriteAuditEvent("webauthn_removed", nil, &a.ID, "",
		fmt.Sprintf(`{"actor":"mciasdb","credential_id":%d}`, *credID)); err != nil {
		fmt.Fprintf(os.Stderr, "warning: write audit event: %v\n", err)
	}

	fmt.Printf("WebAuthn credential %d deleted from account %s\n", *credID, a.Username)
}

func (t *tool) webauthnReset(args []string) {
	fs := flag.NewFlagSet("webauthn reset", flag.ExitOnError)
	id := fs.String("id", "", "account UUID (required)")
	_ = fs.Parse(args)

	if *id == "" {
		fatalf("webauthn reset: --id is required")
	}

	a, err := t.db.GetAccountByUUID(*id)
	if err != nil {
		fatalf("get account: %v", err)
	}

	count, err := t.db.DeleteAllWebAuthnCredentials(a.ID)
	if err != nil {
		fatalf("delete all webauthn credentials: %v", err)
	}

	if err := t.db.WriteAuditEvent("webauthn_removed", nil, &a.ID, "",
		fmt.Sprintf(`{"actor":"mciasdb","action":"reset_webauthn","count":%d}`, count)); err != nil {
		fmt.Fprintf(os.Stderr, "warning: write audit event: %v\n", err)
	}

	fmt.Printf("Removed %d WebAuthn credential(s) from account %s\n", count, a.Username)
}
