// Adds the two POS roles to app_roles.
//
// `app_roles` has no sequence on roleid — every id in it was assigned by hand —
// so 7 and 8 are written explicitly and must match models.PosRoleSupervisor and
// models.PosRoleCashier.
//
// configid is left NULL deliberately. Every other row is portal-specific, which
// is why Admin appears twice (3 and 5) and Manager twice (4 and 6). A till is a
// till whichever portal a tenant uses, and duplicating these per config would
// be one more thing to remember on every onboarding.
//
//	go run ./scratch/posroles plan
//	go run ./scratch/posroles apply
package main

import (
	"fmt"
	"log"
	"os"

	"nearle/models"

	"github.com/joho/godotenv"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

func main() {
	mode := "plan"
	if len(os.Args) > 1 {
		mode = os.Args[1]
	}

	_ = godotenv.Load()
	dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
		os.Getenv("DB_HOST"), os.Getenv("DB_PORT"), os.Getenv("DB_USER"),
		os.Getenv("DB_PASSWORD"), os.Getenv("DB_NAME"))
	db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)})
	if err != nil {
		log.Fatal(err)
	}

	wanted := []struct {
		id   int
		name string
	}{
		{models.PosRoleSupervisor, "Supervisor"},
		{models.PosRoleCashier, "Cashier"},
	}

	write := mode == "apply"
	changes := 0

	for _, w := range wanted {
		var existing string
		db.Raw(`SELECT COALESCE(rolename,'') FROM app_roles WHERE roleid = ?`, w.id).Scan(&existing)

		switch {
		case existing == w.name:
			fmt.Printf("  %-4d %-12s already present\n", w.id, w.name)
		case existing != "":
			// Refuses rather than overwrites. Renaming a role that something
			// else already points at would silently re-permission real accounts.
			fmt.Printf("  %-4d OCCUPIED by %q — refusing to overwrite\n", w.id, existing)
		default:
			fmt.Printf("  %-4d %-12s WOULD INSERT\n", w.id, w.name)
			changes++
			if write {
				if err := db.Exec(
					`INSERT INTO app_roles (roleid, rolename, configid) VALUES (?, ?, NULL)`,
					w.id, w.name,
				).Error; err != nil {
					log.Fatalf("inserting role %d: %v", w.id, err)
				}
			}
		}
	}

	fmt.Println()
	if write {
		fmt.Printf("APPLIED %d role(s).\n", changes)
	} else {
		fmt.Printf("%d role(s) would be added. Nothing written — run `apply`.\n", changes)
	}

	var rows []struct {
		Roleid   int
		Rolename string
	}
	db.Raw(`SELECT roleid, COALESCE(rolename,'') AS rolename FROM app_roles ORDER BY roleid`).Scan(&rows)
	fmt.Println("\napp_roles now:")
	for _, r := range rows {
		fmt.Printf("  %-4d %s\n", r.Roleid, r.Rolename)
	}

	if len(rows) > 0 {
		fmt.Println("\n-- undo:")
		fmt.Printf("DELETE FROM app_roles WHERE roleid IN (%d, %d);\n",
			models.PosRoleSupervisor, models.PosRoleCashier)
	}
}
