// Who can actually open a till, across the whole platform.
//
// Read-only. Answers the question the account model raises the moment sign-in
// becomes real: the endpoint is open to every tenant, so *which* of them can
// genuinely reach it, and does anyone reach it who should not.
package main

import (
	"fmt"
	"log"
	"os"

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

func main() {
	_ = 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)
	}

	// The exact predicate posLoginCandidates + PosLogin apply.
	eligible := `
		FROM app_users a
		WHERE LOWER(COALESCE(a.status,'active')) <> 'inactive'
		  AND COALESCE(a.password,'') <> ''
		  AND COALESCE(a.authname,'') <> ''
		  AND COALESCE(a.tenantid,0) > 0
		  AND EXISTS (SELECT 1 FROM tenantlocations l
		              WHERE l.tenantid = a.tenantid
		                AND LOWER(COALESCE(l.status,'active')) <> 'inactive'
		                AND (COALESCE(a.locationid,0) = 0 OR l.locationid = a.locationid))`

	var total, tenants int
	db.Raw(`SELECT COUNT(*) ` + eligible).Scan(&total)
	db.Raw(`SELECT COUNT(DISTINCT a.tenantid) ` + eligible).Scan(&tenants)

	var allUsers, allTenants int
	db.Raw(`SELECT COUNT(*) FROM app_users`).Scan(&allUsers)
	db.Raw(`SELECT COUNT(*) FROM tenants`).Scan(&allTenants)

	fmt.Printf("app_users rows          %d\n", allUsers)
	fmt.Printf("  can open a till       %d\n", total)
	fmt.Printf("tenants                 %d\n", allTenants)
	fmt.Printf("  with a usable login   %d\n\n", tenants)

	// Which tenants, and whether they have a catalogue to sell.
	var rows []struct {
		Tenantid   int
		Tenantname string
		Users      int
		Outlets    int
		Products   int
	}
	db.Raw(`
		SELECT t.tenantid, COALESCE(t.tenantname,'') AS tenantname,
		  (SELECT COUNT(*) FROM app_users a WHERE a.tenantid=t.tenantid
		     AND LOWER(COALESCE(a.status,'active'))<>'inactive'
		     AND COALESCE(a.password,'')<>'' AND COALESCE(a.authname,'')<>'') AS users,
		  (SELECT COUNT(*) FROM tenantlocations l WHERE l.tenantid=t.tenantid
		     AND LOWER(COALESCE(l.status,'active'))<>'inactive') AS outlets,
		  (SELECT COUNT(*) FROM productlocations p WHERE p.tenantid=t.tenantid) AS products
		FROM tenants t
		WHERE EXISTS (SELECT 1 FROM app_users a WHERE a.tenantid=t.tenantid
		     AND LOWER(COALESCE(a.status,'active'))<>'inactive'
		     AND COALESCE(a.password,'')<>'' AND COALESCE(a.authname,'')<>'')
		ORDER BY products DESC, t.tenantid`).Scan(&rows)

	fmt.Printf("%-8s %-34s %6s %8s %9s\n", "tenant", "name", "logins", "outlets", "products")
	fmt.Println("---------------------------------------------------------------------------")
	for _, r := range rows {
		fmt.Printf("%-8d %-34s %6d %8d %9d\n", r.Tenantid, r.Tenantname, r.Users, r.Outlets, r.Products)
	}

	// Roles. The POS login does not check one, so this says who slips through.
	var roles []struct {
		Roleid int
		C      int
	}
	db.Raw(`SELECT COALESCE(a.roleid,0) AS roleid, COUNT(*) AS c ` + eligible + ` GROUP BY 1 ORDER BY c DESC`).Scan(&roles)
	fmt.Println("\neligible logins by roleid:")
	for _, r := range roles {
		fmt.Printf("  role %-4d %d\n", r.Roleid, r.C)
	}
}
