// Code generated by sqlc. DO NOT EDIT.
// versions:
//   sqlc v1.27.0
// source: galon.sql

package db

import (
	"context"

	"github.com/jackc/pgx/v5/pgtype"
	"github.com/shopspring/decimal"
)

const countGalonTransactions = `-- name: CountGalonTransactions :one
SELECT count(*) FROM galon_transactions
WHERE ($1::text IS NULL OR status = $1)
  AND ($2::text IS NULL OR type = $2)
  AND ($3::bigint IS NULL OR $3::bigint <= 0 OR customer_id = $3)
  AND ($4::bigint[] IS NULL OR (store_id IS NOT NULL AND store_id = ANY($4)))
`

type CountGalonTransactionsParams struct {
	Status          pgtype.Text `json:"status"`
	Type            pgtype.Text `json:"type"`
	CustomerID      pgtype.Int8 `json:"customer_id"`
	AllowedStoreIds []int64     `json:"allowed_store_ids"`
}

func (q *Queries) CountGalonTransactions(ctx context.Context, arg CountGalonTransactionsParams) (int64, error) {
	row := q.db.QueryRow(ctx, countGalonTransactions,
		arg.Status,
		arg.Type,
		arg.CustomerID,
		arg.AllowedStoreIds,
	)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const createGalonTransaction = `-- name: CreateGalonTransaction :one
INSERT INTO galon_transactions (transaction_number, customer_id, type, fulfillment_mode, product_id,
       quantity, unit_price, deposit_amount, status, notes, created_by, store_id, gallon_code)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13)
RETURNING id, transaction_number, customer_id, type, fulfillment_mode, product_id, quantity, unit_price, deposit_amount, loan_amount, loan_returned, status, gallon_code, notes, created_by, store_id, created_at, updated_at
`

type CreateGalonTransactionParams struct {
	TransactionNumber string          `json:"transaction_number"`
	CustomerID        int64           `json:"customer_id"`
	Type              string          `json:"type"`
	FulfillmentMode   string          `json:"fulfillment_mode"`
	ProductID         pgtype.Int8     `json:"product_id"`
	Quantity          decimal.Decimal `json:"quantity"`
	UnitPrice         decimal.Decimal `json:"unit_price"`
	DepositAmount     decimal.Decimal `json:"deposit_amount"`
	Status            string          `json:"status"`
	Notes             pgtype.Text     `json:"notes"`
	CreatedBy         pgtype.Int8     `json:"created_by"`
	StoreID           pgtype.Int8     `json:"store_id"`
	GallonCode        pgtype.Text     `json:"gallon_code"`
}

func (q *Queries) CreateGalonTransaction(ctx context.Context, arg CreateGalonTransactionParams) (GalonTransaction, error) {
	row := q.db.QueryRow(ctx, createGalonTransaction,
		arg.TransactionNumber,
		arg.CustomerID,
		arg.Type,
		arg.FulfillmentMode,
		arg.ProductID,
		arg.Quantity,
		arg.UnitPrice,
		arg.DepositAmount,
		arg.Status,
		arg.Notes,
		arg.CreatedBy,
		arg.StoreID,
		arg.GallonCode,
	)
	var i GalonTransaction
	err := row.Scan(
		&i.ID,
		&i.TransactionNumber,
		&i.CustomerID,
		&i.Type,
		&i.FulfillmentMode,
		&i.ProductID,
		&i.Quantity,
		&i.UnitPrice,
		&i.DepositAmount,
		&i.LoanAmount,
		&i.LoanReturned,
		&i.Status,
		&i.GallonCode,
		&i.Notes,
		&i.CreatedBy,
		&i.StoreID,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const galonInventoryStatus = `-- name: GalonInventoryStatus :one
SELECT
  coalesce(sum(quantity) FILTER (
    WHERE type = 'borrow_galon' AND status = 'completed' AND loan_returned = false
  ), 0)::bigint AS outstanding_loans,
  coalesce(sum(quantity) FILTER (
    WHERE fulfillment_mode = 'delivery' AND status = 'pending'
  ), 0)::bigint AS in_delivery
FROM galon_transactions
WHERE ($1::bigint[] IS NULL
       OR (store_id IS NOT NULL AND store_id = ANY($1)))
`

type GalonInventoryStatusRow struct {
	OutstandingLoans int64 `json:"outstanding_loans"`
	InDelivery       int64 `json:"in_delivery"`
}

// Counts for the POS stat tiles. Each is a different question, so they are
// three different predicates rather than one GROUP BY over status.
//
// outstanding_loans is DERIVABLE: a borrow_galon that reached 'completed' and
// has not been returned. ReturnGalon (internal/galon/service.go) accepts only
// borrow_galon and flips loan_returned, so this pair is exactly "galons
// currently in a customer's hands". 'completed' is required so a pending
// borrow — not yet handed over — is not counted as out with the customer.
//
// in_delivery is DERIVABLE: a delivery-mode transaction still pending, i.e.
// ordered to be delivered and not yet fulfilled.
//
// There is deliberately no third column. 'diToko' (galons held at the store)
// is a PER-UNIT state — the POS mock documents GALON_UNIT_STATUS as
// di_toko / dipinjam / dikembalikan — and there is no galon unit registry to
// read it from: no such table exists, gallon_code is NULL on every row, and no
// unit status column exists anywhere. Summing completed pickups would answer a
// different question (goods collected over time) while sitting under a label
// that claims a physical count, which is the same fabrication this query
// replaces. The handler returns null for it; the POS renders "—".
//
// The store filter matches CountGalonTransactions so the tiles are tenant
// scoped exactly like the list behind them.
func (q *Queries) GalonInventoryStatus(ctx context.Context, allowedStoreIds []int64) (GalonInventoryStatusRow, error) {
	row := q.db.QueryRow(ctx, galonInventoryStatus, allowedStoreIds)
	var i GalonInventoryStatusRow
	err := row.Scan(&i.OutstandingLoans, &i.InDelivery)
	return i, err
}

const getGallonInfoByCode = `-- name: GetGallonInfoByCode :one
SELECT gallon_code,
       count(*)::bigint AS refill_count,
       max(created_at)::timestamptz AS last_refill_at
FROM galon_transactions
WHERE gallon_code = $1::text
  AND ($2::bigint[] IS NULL OR (store_id IS NOT NULL AND store_id = ANY($2)))
GROUP BY gallon_code
`

type GetGallonInfoByCodeParams struct {
	Code            string  `json:"code"`
	AllowedStoreIds []int64 `json:"allowed_store_ids"`
}

type GetGallonInfoByCodeRow struct {
	GallonCode   pgtype.Text        `json:"gallon_code"`
	RefillCount  int64              `json:"refill_count"`
	LastRefillAt pgtype.Timestamptz `json:"last_refill_at"`
}

func (q *Queries) GetGallonInfoByCode(ctx context.Context, arg GetGallonInfoByCodeParams) (GetGallonInfoByCodeRow, error) {
	row := q.db.QueryRow(ctx, getGallonInfoByCode, arg.Code, arg.AllowedStoreIds)
	var i GetGallonInfoByCodeRow
	err := row.Scan(&i.GallonCode, &i.RefillCount, &i.LastRefillAt)
	return i, err
}

const getGalonTransactionByID = `-- name: GetGalonTransactionByID :one
SELECT id, transaction_number, customer_id, type, fulfillment_mode, product_id, quantity, unit_price, deposit_amount, loan_amount, loan_returned, status, gallon_code, notes, created_by, store_id, created_at, updated_at FROM galon_transactions WHERE id=$1
`

func (q *Queries) GetGalonTransactionByID(ctx context.Context, id int64) (GalonTransaction, error) {
	row := q.db.QueryRow(ctx, getGalonTransactionByID, id)
	var i GalonTransaction
	err := row.Scan(
		&i.ID,
		&i.TransactionNumber,
		&i.CustomerID,
		&i.Type,
		&i.FulfillmentMode,
		&i.ProductID,
		&i.Quantity,
		&i.UnitPrice,
		&i.DepositAmount,
		&i.LoanAmount,
		&i.LoanReturned,
		&i.Status,
		&i.GallonCode,
		&i.Notes,
		&i.CreatedBy,
		&i.StoreID,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const getGalonTransactionByIDForUpdate = `-- name: GetGalonTransactionByIDForUpdate :one
SELECT id, transaction_number, customer_id, type, fulfillment_mode, product_id, quantity, unit_price, deposit_amount, loan_amount, loan_returned, status, gallon_code, notes, created_by, store_id, created_at, updated_at FROM galon_transactions WHERE id=$1 FOR UPDATE
`

func (q *Queries) GetGalonTransactionByIDForUpdate(ctx context.Context, id int64) (GalonTransaction, error) {
	row := q.db.QueryRow(ctx, getGalonTransactionByIDForUpdate, id)
	var i GalonTransaction
	err := row.Scan(
		&i.ID,
		&i.TransactionNumber,
		&i.CustomerID,
		&i.Type,
		&i.FulfillmentMode,
		&i.ProductID,
		&i.Quantity,
		&i.UnitPrice,
		&i.DepositAmount,
		&i.LoanAmount,
		&i.LoanReturned,
		&i.Status,
		&i.GallonCode,
		&i.Notes,
		&i.CreatedBy,
		&i.StoreID,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const listGalonTransactions = `-- name: ListGalonTransactions :many
SELECT id, transaction_number, customer_id, type, fulfillment_mode, product_id, quantity, unit_price, deposit_amount, loan_amount, loan_returned, status, gallon_code, notes, created_by, store_id, created_at, updated_at FROM galon_transactions
WHERE ($3::text IS NULL OR status = $3)
  AND ($4::text IS NULL OR type = $4)
  AND ($5::bigint IS NULL OR $5::bigint <= 0 OR customer_id = $5)
  AND ($6::bigint[] IS NULL OR (store_id IS NOT NULL AND store_id = ANY($6)))
ORDER BY id DESC
LIMIT $1 OFFSET $2
`

type ListGalonTransactionsParams struct {
	Limit           int32       `json:"limit"`
	Offset          int32       `json:"offset"`
	Status          pgtype.Text `json:"status"`
	Type            pgtype.Text `json:"type"`
	CustomerID      pgtype.Int8 `json:"customer_id"`
	AllowedStoreIds []int64     `json:"allowed_store_ids"`
}

func (q *Queries) ListGalonTransactions(ctx context.Context, arg ListGalonTransactionsParams) ([]GalonTransaction, error) {
	rows, err := q.db.Query(ctx, listGalonTransactions,
		arg.Limit,
		arg.Offset,
		arg.Status,
		arg.Type,
		arg.CustomerID,
		arg.AllowedStoreIds,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []GalonTransaction
	for rows.Next() {
		var i GalonTransaction
		if err := rows.Scan(
			&i.ID,
			&i.TransactionNumber,
			&i.CustomerID,
			&i.Type,
			&i.FulfillmentMode,
			&i.ProductID,
			&i.Quantity,
			&i.UnitPrice,
			&i.DepositAmount,
			&i.LoanAmount,
			&i.LoanReturned,
			&i.Status,
			&i.GallonCode,
			&i.Notes,
			&i.CreatedBy,
			&i.StoreID,
			&i.CreatedAt,
			&i.UpdatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listGalonTransactionsByCode = `-- name: ListGalonTransactionsByCode :many
SELECT id, transaction_number, customer_id, type, fulfillment_mode, product_id, quantity, unit_price, deposit_amount, loan_amount, loan_returned, status, gallon_code, notes, created_by, store_id, created_at, updated_at FROM galon_transactions
WHERE gallon_code = $1::text
  AND ($2::bigint[] IS NULL OR (store_id IS NOT NULL AND store_id = ANY($2)))
LIMIT $3::int
`

type ListGalonTransactionsByCodeParams struct {
	Code            string  `json:"code"`
	AllowedStoreIds []int64 `json:"allowed_store_ids"`
	Limit           int32   `json:"limit"`
}

func (q *Queries) ListGalonTransactionsByCode(ctx context.Context, arg ListGalonTransactionsByCodeParams) ([]GalonTransaction, error) {
	rows, err := q.db.Query(ctx, listGalonTransactionsByCode, arg.Code, arg.AllowedStoreIds, arg.Limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []GalonTransaction
	for rows.Next() {
		var i GalonTransaction
		if err := rows.Scan(
			&i.ID,
			&i.TransactionNumber,
			&i.CustomerID,
			&i.Type,
			&i.FulfillmentMode,
			&i.ProductID,
			&i.Quantity,
			&i.UnitPrice,
			&i.DepositAmount,
			&i.LoanAmount,
			&i.LoanReturned,
			&i.Status,
			&i.GallonCode,
			&i.Notes,
			&i.CreatedBy,
			&i.StoreID,
			&i.CreatedAt,
			&i.UpdatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const setGalonLoan = `-- name: SetGalonLoan :one
UPDATE galon_transactions
SET loan_amount=$2, loan_returned=$3
WHERE id=$1
RETURNING id, transaction_number, customer_id, type, fulfillment_mode, product_id, quantity, unit_price, deposit_amount, loan_amount, loan_returned, status, gallon_code, notes, created_by, store_id, created_at, updated_at
`

type SetGalonLoanParams struct {
	ID           int64           `json:"id"`
	LoanAmount   decimal.Decimal `json:"loan_amount"`
	LoanReturned bool            `json:"loan_returned"`
}

func (q *Queries) SetGalonLoan(ctx context.Context, arg SetGalonLoanParams) (GalonTransaction, error) {
	row := q.db.QueryRow(ctx, setGalonLoan, arg.ID, arg.LoanAmount, arg.LoanReturned)
	var i GalonTransaction
	err := row.Scan(
		&i.ID,
		&i.TransactionNumber,
		&i.CustomerID,
		&i.Type,
		&i.FulfillmentMode,
		&i.ProductID,
		&i.Quantity,
		&i.UnitPrice,
		&i.DepositAmount,
		&i.LoanAmount,
		&i.LoanReturned,
		&i.Status,
		&i.GallonCode,
		&i.Notes,
		&i.CreatedBy,
		&i.StoreID,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const setGalonTransactionStatus = `-- name: SetGalonTransactionStatus :execrows
UPDATE galon_transactions SET status=$2, updated_at=now() WHERE id=$1
`

type SetGalonTransactionStatusParams struct {
	ID     int64  `json:"id"`
	Status string `json:"status"`
}

func (q *Queries) SetGalonTransactionStatus(ctx context.Context, arg SetGalonTransactionStatusParams) (int64, error) {
	result, err := q.db.Exec(ctx, setGalonTransactionStatus, arg.ID, arg.Status)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}
