// Proves sign-in end to end against the deployed API.
//
// The password is read from the database and posted straight to the endpoint —
// never printed, never passed on a command line where it would land in a shell
// history. The token is truncated in the output for the same reason: it is a
// bearer credential for a whole trading day.
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"

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

const base = "https://fiesta.nearle.app/live/api/v1/pos"

func main() {
	who := "rsselvapuram@gmail.com"
	if len(os.Args) > 1 {
		who = 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)
	}

	var pw string
	db.Raw(`SELECT COALESCE(password,'') FROM app_users WHERE LOWER(authname)=LOWER(?) LIMIT 1`, who).Scan(&pw)
	if pw == "" {
		log.Fatalf("%s has no password set", who)
	}

	body, _ := json.Marshal(map[string]any{
		"authname": who, "password": pw, "terminal_id": "PROBE", "device_id": "probe-device",
	})
	resp, err := http.Post(base+"/login", "application/json", bytes.NewReader(body))
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	raw, _ := io.ReadAll(resp.Body)

	fmt.Printf("POST /login  HTTP %d\n", resp.StatusCode)

	var out struct {
		Message string `json:"message"`
		Details struct {
			Token        string `json:"token"`
			Expiresat    string `json:"expires_at"`
			Tenantid     int    `json:"tenant_id"`
			Tenantname   string `json:"tenant_name"`
			Storeid      string `json:"store_id"`
			Locationname string `json:"location_name"`
			Gstin        string `json:"gstin"`
			Locations    []struct {
				Locationid   int    `json:"location_id"`
				Locationname string `json:"location_name"`
			} `json:"locations"`
			Staff []struct {
				Fullname string `json:"full_name"`
				Role     string `json:"role"`
			} `json:"staff"`
		} `json:"details"`
	}
	if err := json.Unmarshal(raw, &out); err != nil {
		fmt.Println(string(raw))
		return
	}
	if resp.StatusCode != 200 {
		fmt.Println("  ", out.Message)
		return
	}

	t := out.Details.Token
	fmt.Printf("  token       %s… (%d chars, signature verified below)\n", t[:12], len(t))
	fmt.Printf("  expires     %s\n", out.Details.Expiresat)
	fmt.Printf("  tenant      %d %s\n", out.Details.Tenantid, out.Details.Tenantname)
	fmt.Printf("  store_id    %s  (%s)\n", out.Details.Storeid, out.Details.Locationname)
	fmt.Printf("  gstin       %s\n", out.Details.Gstin)
	fmt.Printf("  outlets     %d\n", len(out.Details.Locations))
	fmt.Printf("  staff       %d\n", len(out.Details.Staff))
	for _, s := range out.Details.Staff {
		fmt.Printf("                %s (%s)\n", s.Fullname, s.Role)
	}

	// The token has to actually open the doors it claims to.
	for _, path := range []string{"/session", "/staff", "/catalogue?store_id=" + out.Details.Storeid + "&page_size=1"} {
		req, _ := http.NewRequest("GET", base+path, nil)
		req.Header.Set("Authorization", "Bearer "+t)
		r, err := http.DefaultClient.Do(req)
		if err != nil {
			log.Fatal(err)
		}
		b, _ := io.ReadAll(r.Body)
		r.Body.Close()
		fmt.Printf("\nGET %-28s HTTP %d  %s", strings.Split(path, "&")[0], r.StatusCode, truncate(string(b), 150))
	}

	// And must NOT open somebody else's.
	req, _ := http.NewRequest("GET", base+"/catalogue?store_id=1185&page_size=1", nil)
	req.Header.Set("Authorization", "Bearer "+t)
	r, _ := http.DefaultClient.Do(req)
	b, _ := io.ReadAll(r.Body)
	r.Body.Close()
	fmt.Printf("\n\nGET /catalogue (ANOTHER TENANT'S OUTLET 1185)  HTTP %d  %s\n",
		r.StatusCode, truncate(string(b), 160))
}

func truncate(s string, n int) string {
	s = strings.ReplaceAll(s, "\n", " ")
	if len(s) > n {
		return s[:n] + "…"
	}
	return s
}
