// End-to-end proof for the POS ingest, against the live database.
//
// Sets a temporary price on ONE product so a bill can be rung, and prints the
// exact SQL to undo it. Everything else is read-only.
//
//	go run ./scratch/dbinspect price     # set a test price, print the undo
//	go run ./scratch/dbinspect verify    # show the bill and the stock it moved
//	go run ./scratch/dbinspect restore   # put the price back
package main

import (
	"fmt"
	"log"
	"os"

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

const (
	tenantID   = 1087
	locationID = 1135
	productID  = 6988 // Mysore Banana — 750 units in stock, 8% tax
	testPrice  = 60.00
)

func main() {
	_ = godotenv.Load()

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

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

	switch mode {
	case "price":
		var before float64
		db.Raw(`SELECT COALESCE(price,0) FROM productlocations
		        WHERE tenantid=? AND locationid=? AND productid=?`,
			tenantID, locationID, productID).Scan(&before)

		if err := db.Exec(`UPDATE productlocations SET price = ?
		                   WHERE tenantid=? AND locationid=? AND productid=?`,
			testPrice, tenantID, locationID, productID).Error; err != nil {
			log.Fatal("price:", err)
		}

		fmt.Printf("product %d priced at %.2f (was %.2f)\n", productID, testPrice, before)
		fmt.Printf("\nUNDO:\n  UPDATE productlocations SET price = %.2f\n"+
			"   WHERE tenantid=%d AND locationid=%d AND productid=%d;\n",
			before, tenantID, locationID, productID)

	case "restore":
		if err := db.Exec(`UPDATE productlocations SET price = 0
		                   WHERE tenantid=? AND locationid=? AND productid=?`,
			tenantID, locationID, productID).Error; err != nil {
			log.Fatal("restore:", err)
		}
		fmt.Printf("product %d price restored to 0\n", productID)

	case "verify":
		fmt.Println("=== pos_orders ===")
		var bills []struct {
			Posorderid      int
			Terminalorderid string
			Invoicenumber   string
			Terminalid      string
			Cashiername     string
			Businessdate    string
			Subtotal        float64
			Taxamount       float64
			Roundoff        float64
			Total           float64
			Itemcount       int
			Paymentmode     string
		}
		db.Raw(`SELECT posorderid, terminalorderid, invoicenumber, terminalid,
		               cashiername, businessdate, subtotal, taxamount, roundoff,
		               total, itemcount, paymentmode
		        FROM pos_orders ORDER BY posorderid DESC LIMIT 5`).Scan(&bills)

		if len(bills) == 0 {
			fmt.Println("  (none yet)")
		}
		for _, b := range bills {
			fmt.Printf("  #%d %s  till=%s cashier=%s date=%s\n",
				b.Posorderid, b.Invoicenumber, b.Terminalid, b.Cashiername, b.Businessdate)
			fmt.Printf("     uuid=%s\n", b.Terminalorderid)
			fmt.Printf("     subtotal=%.2f tax=%.2f roundoff=%.2f total=%.2f items=%d paid=%s\n",
				b.Subtotal, b.Taxamount, b.Roundoff, b.Total, b.Itemcount, b.Paymentmode)
		}

		fmt.Println("\n=== pos_order_items ===")
		var items []struct {
			Posorderid  int
			Productid   int
			Productname string
			Quantity    float64
			Unitprice   float64
			Gstrate     float64
			Taxamount   float64
			Linetotal   float64
		}
		db.Raw(`SELECT posorderid, productid, productname, quantity, unitprice,
		               gstrate, taxamount, linetotal
		        FROM pos_order_items ORDER BY posorderitemid DESC LIMIT 10`).Scan(&items)
		for _, i := range items {
			fmt.Printf("  bill#%d  %-18.18s qty=%-6.2f @%-8.2f gst=%-6.2f tax=%-7.2f line=%.2f\n",
				i.Posorderid, i.Productname, i.Quantity, i.Unitprice,
				i.Gstrate, i.Taxamount, i.Linetotal)
		}

		fmt.Println("\n=== stock ledger for the test product ===")
		var moves []struct {
			Productstockid int
			Quantity       int
			Stocktype      string
			Stockdate      string
		}
		db.Raw(`SELECT productstockid, quantity, stocktype,
		               TO_CHAR(stockdate,'YYYY-MM-DD HH24:MI:SS') AS stockdate
		        FROM productstocks
		        WHERE tenantid=? AND locationid=? AND productid=?
		        ORDER BY productstockid DESC LIMIT 5`,
			tenantID, locationID, productID).Scan(&moves)
		for _, m := range moves {
			fmt.Printf("  #%d  %-4s qty=%-6d %s\n",
				m.Productstockid, m.Stocktype, m.Quantity, m.Stockdate)
		}

		var balance float64
		db.Raw(`SELECT COALESCE(
		           SUM(CASE WHEN LOWER(stocktype)='in'  THEN quantity ELSE 0 END) -
		           SUM(CASE WHEN LOWER(stocktype)='out' THEN quantity ELSE 0 END), 0)
		        FROM productstocks WHERE tenantid=? AND locationid=? AND productid=?`,
			tenantID, locationID, productID).Scan(&balance)
		fmt.Printf("  balance now: %.0f\n", balance)

	case "cleanup":
		cleanup(db)

	case "columns":
		for _, t := range []string{"products", "productlocations", "productstocks"} {
			fmt.Printf("=== %s ===\n", t)
			var cols []struct {
				ColumnName string
				DataType   string
			}
			db.Raw(`SELECT column_name, data_type FROM information_schema.columns
			        WHERE table_name = ? ORDER BY ordinal_position`, t).Scan(&cols)
			for _, c := range cols {
				marker := ""
				n := c.ColumnName
				if n == "created" || n == "updated" || n == "updated_at" ||
					n == "stockdate" || n == "modified" {
					marker = "   <-- timestamp"
				}
				fmt.Printf("  %-24s %s%s\n", c.ColumnName, c.DataType, marker)
			}
		}

	case "customer":
		fmt.Println("=== customers matching the uplink probe ===")
		showCustomer(db, "9840012345")

	default:
		log.Fatalf("unknown mode %q — use price, verify, restore or cleanup", mode)
	}
}
