package main

import (
	"fmt"

	"gorm.io/gorm"
)

// cleanup removes everything the end-to-end proof wrote to the live database.
//
// Three things, in an order that leaves nothing half-undone: the stock the test
// bills consumed is returned, the bills themselves are deleted, and the price
// that was set to make a product sellable goes back to what it was.
//
// The two test bills are named explicitly rather than deleted by date or by
// "everything in pos_orders" — a table that will hold real takings tomorrow is
// not one to run an unbounded DELETE against.
// Every mobile the probes registered, so a cleanup run leaves nothing behind.
var probeMobiles = []string{"9840012345", "9840099999", "9840077777"}

var testOrderIDs = []string{
	"11111111-2222-4333-8444-555555555555", // the HTTP probe
	"99999999-8888-4777-8666-555555555555", // the MQTT probe
}

func cleanup(db *gorm.DB) {
	var billIDs []int
	db.Raw(`SELECT posorderid FROM pos_orders WHERE terminalorderid IN ?`,
		testOrderIDs).Scan(&billIDs)

	if len(billIDs) == 0 {
		fmt.Println("no test bills found — nothing to undo")
	}

	// Stock first. Deleting the bills before returning what they consumed would
	// leave the ledger short with nothing left to explain why.
	var consumed []struct {
		Productid int
		Quantity  float64
	}
	db.Raw(`SELECT productid, SUM(quantity) AS quantity
	        FROM pos_order_items WHERE posorderid IN ?
	        GROUP BY productid`, billIDs).Scan(&consumed)

	for _, c := range consumed {
		qty := int(c.Quantity)
		if float64(qty) < c.Quantity {
			qty++ // the ingest rounded up, so the reversal must too
		}
		if err := db.Exec(`
			INSERT INTO productstocks (tenantid, stockdate, locationid, productid,
			                           quantity, stocktype, status)
			VALUES (?, NOW(), ?, ?, ?, 'in', 'Active')`,
			tenantID, locationID, c.Productid, qty).Error; err != nil {
			fmt.Println("  return stock:", err)
			continue
		}
		fmt.Printf("  returned %d units of product %d\n", qty, c.Productid)
	}

	if len(billIDs) > 0 {
		db.Exec(`DELETE FROM pos_order_items WHERE posorderid IN ?`, billIDs)
		db.Exec(`DELETE FROM pos_orders WHERE posorderid IN ?`, billIDs)
		fmt.Printf("  deleted %d test bill(s)\n", len(billIDs))
	}

	db.Exec(`UPDATE productlocations SET price = 0
	         WHERE tenantid=? AND locationid=? AND productid=?`,
		tenantID, locationID, productID)
	fmt.Printf("  product %d price restored to 0\n", productID)

	// The shopper the probes created. Removed only when nothing references it —
	// a customer row attached to a real order is not test data any more.
	for _, mobile := range probeMobiles {
		// A customer row attached to a real order is not test data any more.
		var referenced int
		db.Raw(`SELECT COUNT(*) FROM orders WHERE customerid IN
		          (SELECT customerid FROM customers WHERE contactno = ?)`,
			mobile).Scan(&referenced)
		if referenced > 0 {
			fmt.Printf("  customer %s left in place — %d order(s) reference it\n",
				mobile, referenced)
			continue
		}
		res := db.Exec(`DELETE FROM customers WHERE contactno = ?`, mobile)
		if res.RowsAffected > 0 {
			fmt.Printf("  removed probe customer %s\n", mobile)
		}
	}

	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("  product %d balance back to %.0f\n", productID, balance)
}

// showCustomer reports whether the registration probe reached the customers
// table, and under which id — the question an ack alone cannot answer.
func showCustomer(db *gorm.DB, mobile string) {
	var rows []struct {
		Customerid    int
		Firstname     string
		Contactno     string
		Applocationid int
	}
	db.Raw(`SELECT customerid, COALESCE(firstname,'') AS firstname,
	               COALESCE(contactno,'') AS contactno,
	               COALESCE(applocationid,0) AS applocationid
	        FROM customers WHERE contactno = ?`, mobile).Scan(&rows)

	if len(rows) == 0 {
		fmt.Printf("  no customer with contactno %s\n", mobile)
		return
	}
	for _, r := range rows {
		fmt.Printf("  customerid=%d %q contactno=%s applocid=%d\n",
			r.Customerid, r.Firstname, r.Contactno, r.Applocationid)
	}
}
