package routes

import (
	"nearle/facade"
	"nearle/middleware"

	"github.com/gofiber/fiber/v2"
)

// Routes for the Nearle POS terminal.
//
// The paths are fixed by the till, which appends `/orders`, `/customers` and
// `/catalogue` to whatever base URL a shop enters in Settings. Set that base to
// this group — `https://your-host/live/api/v1/pos` — and the three line up.
//
// Kept in their own group rather than folded into the order routes because a
// terminal authenticates as a device, not as a signed-in user, and because
// these answer with a bare ack rather than the web app's response envelope.
func RegisterPosRoutes(api fiber.Router, f *facade.Facade) {

	pos := api.Group("/v1/pos")

	// Sign-in, and the only route on this group that runs before the guard —
	// it is where a session comes from. A till posts the same `app_users`
	// credentials the web console takes, and gets back a token plus the outlet
	// that account is entitled to. The store id it will bill under is decided
	// here, from the user's record, instead of being typed into Settings and
	// taken on trust.
	pos.Post("/login", f.PosController.Login)

	// Everything past this point carries the session.
	//
	// The guard verifies the token and refuses a request naming an outlet the
	// token's tenant does not own. Until `POS_AUTH_REQUIRED=true` is set it
	// lets an unauthenticated request through, so the terminals already
	// trading do not stop the day this deploys — see middleware.PosAuth.
	pos.Use(middleware.PosAuth(f.PosService()))

	pos.Get("/session", f.PosController.Session)

	// Who may ring a bill here. Deliberately takes no location parameter — the
	// answer carries PINs, so the outlet comes from the caller's own token.
	pos.Get("/staff", f.PosController.Staff)

	// Signing on by PIN, once a supervisor has opened the terminal with a real
	// password. Sits behind the guard on purpose — see PinLogin.
	pos.Post("/login/pin", f.PosController.PinLogin)

	// The shop's own counter staff. A supervisor creates their cashiers; the
	// outlet is always the caller's own, read from their token.
	pos.Get("/users", f.PosController.ListPosUsers)
	pos.Post("/users", f.PosController.CreatePosUser)
	pos.Put("/users", f.PosController.UpdatePosUser)
	pos.Delete("/users", f.PosController.DeletePosUser)

	pos.Post("/orders", f.PosController.IngestOrders)
	pos.Post("/customers", f.PosController.IngestCustomers)
	pos.Get("/catalogue", f.PosController.Catalogue)

	// The 30-second heartbeat, for tills on the HTTP route. The broker carries
	// the same payload for tills on MQTT; both land in the same Redis record,
	// so the fleet board cannot tell them apart and does not need to.
	pos.Post("/health", f.PosController.IngestHealth)

	// Counter sales, read back out. The ingest above only ever writes; without
	// these a committed bill is unreachable from every screen in the product.
	pos.Get("/sales", f.PosController.GetSales)
	pos.Get("/sales/detail", f.PosController.GetSaleDetail)
	pos.Get("/sales/summary", f.PosController.GetSalesSummary)

	// Terminal presence, read from Redis. What the rider app's POS board and a
	// support call both hit — the tills themselves publish health over the
	// broker rather than posting it here.
	pos.Get("/health/terminal", f.PosController.TerminalHealth)
	pos.Get("/health/location", f.PosController.LocationHealth)

	registerPosStaffConsoleRoutes(api, f)
}

// Till staff, managed from the web console rather than from a counter.
//
// Under `/web` and `/mob` rather than `/pos`, because the callers are the back
// office and the daily app — neither holds a terminal session, and putting them
// behind the terminal guard would lock out the very screen an admin uses to set
// a shop up in the first place.
//
// They run the same service calls as `/pos/users`. A supervisor created here is
// the same row, with the same rules applied, as one created at a till.
//
// The outlet is asserted rather than proved, which is the real difference and
// the weaker half: a terminal signs its outlet, a console just names one. It is
// checked against the tenant before anything is written, and these should move
// behind a session guard as soon as the console can hold one — until then, this
// mints till credentials on the strength of an unauthenticated request, exactly
// like every other route in this group.
func registerPosStaffConsoleRoutes(api fiber.Router, f *facade.Facade) {
	for _, group := range []string{"/v1/web/tenants", "/v1/mob/tenants"} {
		g := api.Group(group)

		// Served rather than hardcoded, so a console offering the choice does
		// not have to know that supervisor is 7.
		g.Get("/posroles", f.PosController.WebPosRoles)

		g.Get("/getposusers", f.PosController.WebListPosUsers)
		g.Post("/createposuser", f.PosController.WebCreatePosUser)
		g.Put("/updateposuser", f.PosController.WebUpdatePosUser)
		g.Delete("/deleteposuser", f.PosController.WebDeletePosUser)
	}
}
