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

package db

import (
	"context"

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

const countCustomersForMembership = `-- name: CountCustomersForMembership :one
SELECT count(*) FROM customers WHERE id = $1 AND deleted_at IS NULL
`

func (q *Queries) CountCustomersForMembership(ctx context.Context, id int64) (int64, error) {
	row := q.db.QueryRow(ctx, countCustomersForMembership, id)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const countMemberships = `-- name: CountMemberships :one
SELECT count(*) FROM memberships m
JOIN customers c ON c.id = m.customer_id
WHERE ($1::text IS NULL
       OR m.member_number ILIKE '%' || $1 || '%'
       OR c.name ILIKE '%' || $1 || '%')
  AND ($2::text IS NULL OR m.tier = $2)
  AND ($3::boolean IS NULL OR m.is_active = $3)
`

type CountMembershipsParams struct {
	Search   pgtype.Text `json:"search"`
	Tier     pgtype.Text `json:"tier"`
	IsActive pgtype.Bool `json:"is_active"`
}

func (q *Queries) CountMemberships(ctx context.Context, arg CountMembershipsParams) (int64, error) {
	row := q.db.QueryRow(ctx, countMemberships, arg.Search, arg.Tier, arg.IsActive)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const createMembership = `-- name: CreateMembership :one
INSERT INTO memberships (member_number, customer_id, tier, joined_date, is_active, notes, created_by)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id
`

type CreateMembershipParams struct {
	MemberNumber string      `json:"member_number"`
	CustomerID   int64       `json:"customer_id"`
	Tier         string      `json:"tier"`
	JoinedDate   pgtype.Date `json:"joined_date"`
	IsActive     bool        `json:"is_active"`
	Notes        pgtype.Text `json:"notes"`
	CreatedBy    pgtype.Int8 `json:"created_by"`
}

func (q *Queries) CreateMembership(ctx context.Context, arg CreateMembershipParams) (int64, error) {
	row := q.db.QueryRow(ctx, createMembership,
		arg.MemberNumber,
		arg.CustomerID,
		arg.Tier,
		arg.JoinedDate,
		arg.IsActive,
		arg.Notes,
		arg.CreatedBy,
	)
	var id int64
	err := row.Scan(&id)
	return id, err
}

const createMembershipTier = `-- name: CreateMembershipTier :one
INSERT INTO membership_tiers (code, name, discount_type, discount_value, min_orders, min_spend, is_active)
VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING id, code, name, discount_type, discount_value, min_orders, min_spend, is_active, created_at, updated_at
`

type CreateMembershipTierParams struct {
	Code          string          `json:"code"`
	Name          string          `json:"name"`
	DiscountType  string          `json:"discount_type"`
	DiscountValue decimal.Decimal `json:"discount_value"`
	MinOrders     int32           `json:"min_orders"`
	MinSpend      decimal.Decimal `json:"min_spend"`
	IsActive      bool            `json:"is_active"`
}

func (q *Queries) CreateMembershipTier(ctx context.Context, arg CreateMembershipTierParams) (MembershipTier, error) {
	row := q.db.QueryRow(ctx, createMembershipTier,
		arg.Code,
		arg.Name,
		arg.DiscountType,
		arg.DiscountValue,
		arg.MinOrders,
		arg.MinSpend,
		arg.IsActive,
	)
	var i MembershipTier
	err := row.Scan(
		&i.ID,
		&i.Code,
		&i.Name,
		&i.DiscountType,
		&i.DiscountValue,
		&i.MinOrders,
		&i.MinSpend,
		&i.IsActive,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const createMembershipTierConfigHistory = `-- name: CreateMembershipTierConfigHistory :exec
INSERT INTO membership_tier_config_history
  (membership_tier_id, from_discount_type, from_discount_value, to_discount_type, to_discount_value, from_min_orders, to_min_orders, from_min_spend, to_min_spend, reason, changed_by)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)
`

type CreateMembershipTierConfigHistoryParams struct {
	MembershipTierID  int64               `json:"membership_tier_id"`
	FromDiscountType  pgtype.Text         `json:"from_discount_type"`
	FromDiscountValue decimal.NullDecimal `json:"from_discount_value"`
	ToDiscountType    string              `json:"to_discount_type"`
	ToDiscountValue   decimal.Decimal     `json:"to_discount_value"`
	FromMinOrders     pgtype.Int4         `json:"from_min_orders"`
	ToMinOrders       pgtype.Int4         `json:"to_min_orders"`
	FromMinSpend      decimal.NullDecimal `json:"from_min_spend"`
	ToMinSpend        decimal.NullDecimal `json:"to_min_spend"`
	Reason            pgtype.Text         `json:"reason"`
	ChangedBy         pgtype.Int8         `json:"changed_by"`
}

func (q *Queries) CreateMembershipTierConfigHistory(ctx context.Context, arg CreateMembershipTierConfigHistoryParams) error {
	_, err := q.db.Exec(ctx, createMembershipTierConfigHistory,
		arg.MembershipTierID,
		arg.FromDiscountType,
		arg.FromDiscountValue,
		arg.ToDiscountType,
		arg.ToDiscountValue,
		arg.FromMinOrders,
		arg.ToMinOrders,
		arg.FromMinSpend,
		arg.ToMinSpend,
		arg.Reason,
		arg.ChangedBy,
	)
	return err
}

const createMembershipTierHistory = `-- name: CreateMembershipTierHistory :exec
INSERT INTO membership_tier_history (membership_id, from_tier, to_tier, reason, changed_by)
VALUES ($1, $2, $3, $4, $5)
`

type CreateMembershipTierHistoryParams struct {
	MembershipID int64       `json:"membership_id"`
	FromTier     pgtype.Text `json:"from_tier"`
	ToTier       string      `json:"to_tier"`
	Reason       string      `json:"reason"`
	ChangedBy    pgtype.Int8 `json:"changed_by"`
}

func (q *Queries) CreateMembershipTierHistory(ctx context.Context, arg CreateMembershipTierHistoryParams) error {
	_, err := q.db.Exec(ctx, createMembershipTierHistory,
		arg.MembershipID,
		arg.FromTier,
		arg.ToTier,
		arg.Reason,
		arg.ChangedBy,
	)
	return err
}

const getMembershipByCustomer = `-- name: GetMembershipByCustomer :one
SELECT m.id, m.member_number, m.customer_id, m.tier, m.points, m.joined_date::text AS joined_date,
       m.is_active, m.notes, m.created_at, m.updated_at,
       c.code AS customer_code, c.name AS customer_name, c.user_id
FROM memberships m
JOIN customers c ON c.id = m.customer_id
WHERE m.customer_id = $1
`

type GetMembershipByCustomerRow struct {
	ID           int64              `json:"id"`
	MemberNumber string             `json:"member_number"`
	CustomerID   int64              `json:"customer_id"`
	Tier         string             `json:"tier"`
	Points       int64              `json:"points"`
	JoinedDate   string             `json:"joined_date"`
	IsActive     bool               `json:"is_active"`
	Notes        pgtype.Text        `json:"notes"`
	CreatedAt    pgtype.Timestamptz `json:"created_at"`
	UpdatedAt    pgtype.Timestamptz `json:"updated_at"`
	CustomerCode string             `json:"customer_code"`
	CustomerName string             `json:"customer_name"`
	UserID       pgtype.Int8        `json:"user_id"`
}

func (q *Queries) GetMembershipByCustomer(ctx context.Context, customerID int64) (GetMembershipByCustomerRow, error) {
	row := q.db.QueryRow(ctx, getMembershipByCustomer, customerID)
	var i GetMembershipByCustomerRow
	err := row.Scan(
		&i.ID,
		&i.MemberNumber,
		&i.CustomerID,
		&i.Tier,
		&i.Points,
		&i.JoinedDate,
		&i.IsActive,
		&i.Notes,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.CustomerCode,
		&i.CustomerName,
		&i.UserID,
	)
	return i, err
}

const getMembershipByID = `-- name: GetMembershipByID :one

SELECT m.id, m.member_number, m.customer_id, m.tier, m.points, m.joined_date::text AS joined_date,
       m.is_active, m.notes, m.created_at, m.updated_at,
       c.code AS customer_code, c.name AS customer_name, c.user_id
FROM memberships m
JOIN customers c ON c.id = m.customer_id
WHERE m.id = $1
`

type GetMembershipByIDRow struct {
	ID           int64              `json:"id"`
	MemberNumber string             `json:"member_number"`
	CustomerID   int64              `json:"customer_id"`
	Tier         string             `json:"tier"`
	Points       int64              `json:"points"`
	JoinedDate   string             `json:"joined_date"`
	IsActive     bool               `json:"is_active"`
	Notes        pgtype.Text        `json:"notes"`
	CreatedAt    pgtype.Timestamptz `json:"created_at"`
	UpdatedAt    pgtype.Timestamptz `json:"updated_at"`
	CustomerCode string             `json:"customer_code"`
	CustomerName string             `json:"customer_name"`
	UserID       pgtype.Int8        `json:"user_id"`
}

// Phase 6 item 3 (scaffolding): membership identity and tiers (business-rules.md
// §13.1). Only the confirmed rules are queryable here: the
// User -> Customer -> Membership split and exactly three tiers. Benefit
// resolution has no queries yet because the formulas are unresolved.
func (q *Queries) GetMembershipByID(ctx context.Context, id int64) (GetMembershipByIDRow, error) {
	row := q.db.QueryRow(ctx, getMembershipByID, id)
	var i GetMembershipByIDRow
	err := row.Scan(
		&i.ID,
		&i.MemberNumber,
		&i.CustomerID,
		&i.Tier,
		&i.Points,
		&i.JoinedDate,
		&i.IsActive,
		&i.Notes,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.CustomerCode,
		&i.CustomerName,
		&i.UserID,
	)
	return i, err
}

const getMembershipByNumber = `-- name: GetMembershipByNumber :one
SELECT m.id, m.member_number, m.customer_id, m.tier, m.points, m.joined_date::text AS joined_date,
       m.is_active, m.notes, m.created_at, m.updated_at,
       c.code AS customer_code, c.name AS customer_name, c.user_id
FROM memberships m
JOIN customers c ON c.id = m.customer_id
WHERE m.member_number = $1
`

type GetMembershipByNumberRow struct {
	ID           int64              `json:"id"`
	MemberNumber string             `json:"member_number"`
	CustomerID   int64              `json:"customer_id"`
	Tier         string             `json:"tier"`
	Points       int64              `json:"points"`
	JoinedDate   string             `json:"joined_date"`
	IsActive     bool               `json:"is_active"`
	Notes        pgtype.Text        `json:"notes"`
	CreatedAt    pgtype.Timestamptz `json:"created_at"`
	UpdatedAt    pgtype.Timestamptz `json:"updated_at"`
	CustomerCode string             `json:"customer_code"`
	CustomerName string             `json:"customer_name"`
	UserID       pgtype.Int8        `json:"user_id"`
}

func (q *Queries) GetMembershipByNumber(ctx context.Context, memberNumber string) (GetMembershipByNumberRow, error) {
	row := q.db.QueryRow(ctx, getMembershipByNumber, memberNumber)
	var i GetMembershipByNumberRow
	err := row.Scan(
		&i.ID,
		&i.MemberNumber,
		&i.CustomerID,
		&i.Tier,
		&i.Points,
		&i.JoinedDate,
		&i.IsActive,
		&i.Notes,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.CustomerCode,
		&i.CustomerName,
		&i.UserID,
	)
	return i, err
}

const getMembershipByUser = `-- name: GetMembershipByUser :one
SELECT m.id, m.member_number, m.customer_id, m.tier, m.points, m.joined_date::text AS joined_date,
       m.is_active, m.notes, m.created_at, m.updated_at,
       c.code AS customer_code, c.name AS customer_name, c.user_id
FROM memberships m
JOIN customers c ON c.id = m.customer_id
WHERE c.user_id = $1 AND c.deleted_at IS NULL
`

type GetMembershipByUserRow struct {
	ID           int64              `json:"id"`
	MemberNumber string             `json:"member_number"`
	CustomerID   int64              `json:"customer_id"`
	Tier         string             `json:"tier"`
	Points       int64              `json:"points"`
	JoinedDate   string             `json:"joined_date"`
	IsActive     bool               `json:"is_active"`
	Notes        pgtype.Text        `json:"notes"`
	CreatedAt    pgtype.Timestamptz `json:"created_at"`
	UpdatedAt    pgtype.Timestamptz `json:"updated_at"`
	CustomerCode string             `json:"customer_code"`
	CustomerName string             `json:"customer_name"`
	UserID       pgtype.Int8        `json:"user_id"`
}

func (q *Queries) GetMembershipByUser(ctx context.Context, userID pgtype.Int8) (GetMembershipByUserRow, error) {
	row := q.db.QueryRow(ctx, getMembershipByUser, userID)
	var i GetMembershipByUserRow
	err := row.Scan(
		&i.ID,
		&i.MemberNumber,
		&i.CustomerID,
		&i.Tier,
		&i.Points,
		&i.JoinedDate,
		&i.IsActive,
		&i.Notes,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.CustomerCode,
		&i.CustomerName,
		&i.UserID,
	)
	return i, err
}

const getMembershipTier = `-- name: GetMembershipTier :one
SELECT id, code, name, discount_type, discount_value, min_orders, min_spend, is_active, created_at, updated_at
FROM membership_tiers WHERE id = $1
`

func (q *Queries) GetMembershipTier(ctx context.Context, id int64) (MembershipTier, error) {
	row := q.db.QueryRow(ctx, getMembershipTier, id)
	var i MembershipTier
	err := row.Scan(
		&i.ID,
		&i.Code,
		&i.Name,
		&i.DiscountType,
		&i.DiscountValue,
		&i.MinOrders,
		&i.MinSpend,
		&i.IsActive,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const getMembershipTierByCode = `-- name: GetMembershipTierByCode :one
SELECT id, code, name, discount_type, discount_value, min_orders, min_spend, is_active, created_at, updated_at
FROM membership_tiers WHERE code = $1
`

func (q *Queries) GetMembershipTierByCode(ctx context.Context, code string) (MembershipTier, error) {
	row := q.db.QueryRow(ctx, getMembershipTierByCode, code)
	var i MembershipTier
	err := row.Scan(
		&i.ID,
		&i.Code,
		&i.Name,
		&i.DiscountType,
		&i.DiscountValue,
		&i.MinOrders,
		&i.MinSpend,
		&i.IsActive,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const listMembershipTierConfigHistory = `-- name: ListMembershipTierConfigHistory :many

SELECT id, membership_tier_id, from_discount_type, from_discount_value,
       to_discount_type, to_discount_value,
       from_min_orders, to_min_orders, from_min_spend, to_min_spend,
       reason, changed_by, changed_at
FROM membership_tier_config_history
WHERE membership_tier_id = $1
ORDER BY id DESC
`

// The tier CONFIG audit trail, as opposed to the per-member tier assignment
// above. CreateTier and UpdateTier both append here inside their transaction
// (service.go RecordTierConfigHistory), so the rows exist — they were simply
// never readable, which made "who raised the gold discount and when"
// unanswerable.
//
// Includes the min_orders / min_spend before/after columns added by migration
// 000077. Rows written before that migration have NULLs in all four, which is
// real history rather than a missing value: the columns did not exist yet.
func (q *Queries) ListMembershipTierConfigHistory(ctx context.Context, membershipTierID int64) ([]MembershipTierConfigHistory, error) {
	rows, err := q.db.Query(ctx, listMembershipTierConfigHistory, membershipTierID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []MembershipTierConfigHistory
	for rows.Next() {
		var i MembershipTierConfigHistory
		if err := rows.Scan(
			&i.ID,
			&i.MembershipTierID,
			&i.FromDiscountType,
			&i.FromDiscountValue,
			&i.ToDiscountType,
			&i.ToDiscountValue,
			&i.FromMinOrders,
			&i.ToMinOrders,
			&i.FromMinSpend,
			&i.ToMinSpend,
			&i.Reason,
			&i.ChangedBy,
			&i.ChangedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listMembershipTierHistory = `-- name: ListMembershipTierHistory :many
SELECT id, membership_id, from_tier, to_tier, reason, changed_by, created_at
FROM membership_tier_history
WHERE membership_id = $1
ORDER BY id DESC
`

func (q *Queries) ListMembershipTierHistory(ctx context.Context, membershipID int64) ([]MembershipTierHistory, error) {
	rows, err := q.db.Query(ctx, listMembershipTierHistory, membershipID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []MembershipTierHistory
	for rows.Next() {
		var i MembershipTierHistory
		if err := rows.Scan(
			&i.ID,
			&i.MembershipID,
			&i.FromTier,
			&i.ToTier,
			&i.Reason,
			&i.ChangedBy,
			&i.CreatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listMembershipTiers = `-- name: ListMembershipTiers :many

SELECT id, code, name, discount_type, discount_value, min_orders, min_spend, is_active, created_at, updated_at
FROM membership_tiers ORDER BY id
`

// STEP 0: database-backed membership tier configuration (business-rules.md §13.1).
func (q *Queries) ListMembershipTiers(ctx context.Context) ([]MembershipTier, error) {
	rows, err := q.db.Query(ctx, listMembershipTiers)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []MembershipTier
	for rows.Next() {
		var i MembershipTier
		if err := rows.Scan(
			&i.ID,
			&i.Code,
			&i.Name,
			&i.DiscountType,
			&i.DiscountValue,
			&i.MinOrders,
			&i.MinSpend,
			&i.IsActive,
			&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 listMemberships = `-- name: ListMemberships :many
SELECT m.id, m.member_number, m.customer_id, m.tier, m.points, m.joined_date::text AS joined_date,
       m.is_active, m.notes, m.created_at, m.updated_at,
       c.code AS customer_code, c.name AS customer_name, c.user_id
FROM memberships m
JOIN customers c ON c.id = m.customer_id
WHERE ($3::text IS NULL
       OR m.member_number ILIKE '%' || $3 || '%'
       OR c.name ILIKE '%' || $3 || '%')
  AND ($4::text IS NULL OR m.tier = $4)
  AND ($5::boolean IS NULL OR m.is_active = $5)
ORDER BY m.member_number
LIMIT $1 OFFSET $2
`

type ListMembershipsParams struct {
	Limit    int32       `json:"limit"`
	Offset   int32       `json:"offset"`
	Search   pgtype.Text `json:"search"`
	Tier     pgtype.Text `json:"tier"`
	IsActive pgtype.Bool `json:"is_active"`
}

type ListMembershipsRow struct {
	ID           int64              `json:"id"`
	MemberNumber string             `json:"member_number"`
	CustomerID   int64              `json:"customer_id"`
	Tier         string             `json:"tier"`
	Points       int64              `json:"points"`
	JoinedDate   string             `json:"joined_date"`
	IsActive     bool               `json:"is_active"`
	Notes        pgtype.Text        `json:"notes"`
	CreatedAt    pgtype.Timestamptz `json:"created_at"`
	UpdatedAt    pgtype.Timestamptz `json:"updated_at"`
	CustomerCode string             `json:"customer_code"`
	CustomerName string             `json:"customer_name"`
	UserID       pgtype.Int8        `json:"user_id"`
}

func (q *Queries) ListMemberships(ctx context.Context, arg ListMembershipsParams) ([]ListMembershipsRow, error) {
	rows, err := q.db.Query(ctx, listMemberships,
		arg.Limit,
		arg.Offset,
		arg.Search,
		arg.Tier,
		arg.IsActive,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListMembershipsRow
	for rows.Next() {
		var i ListMembershipsRow
		if err := rows.Scan(
			&i.ID,
			&i.MemberNumber,
			&i.CustomerID,
			&i.Tier,
			&i.Points,
			&i.JoinedDate,
			&i.IsActive,
			&i.Notes,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.CustomerCode,
			&i.CustomerName,
			&i.UserID,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const setMembershipPoints = `-- name: SetMembershipPoints :execrows
UPDATE memberships SET points = $2, tier = $3, updated_at = now()
WHERE id = $1
`

type SetMembershipPointsParams struct {
	ID     int64  `json:"id"`
	Points int64  `json:"points"`
	Tier   string `json:"tier"`
}

// §20 (membership points): write accrued points and optional tier back.
func (q *Queries) SetMembershipPoints(ctx context.Context, arg SetMembershipPointsParams) (int64, error) {
	result, err := q.db.Exec(ctx, setMembershipPoints, arg.ID, arg.Points, arg.Tier)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const updateMembership = `-- name: UpdateMembership :execrows
UPDATE memberships SET tier = $2, is_active = $3, notes = $4, updated_at = now()
WHERE id = $1
`

type UpdateMembershipParams struct {
	ID       int64       `json:"id"`
	Tier     string      `json:"tier"`
	IsActive bool        `json:"is_active"`
	Notes    pgtype.Text `json:"notes"`
}

func (q *Queries) UpdateMembership(ctx context.Context, arg UpdateMembershipParams) (int64, error) {
	result, err := q.db.Exec(ctx, updateMembership,
		arg.ID,
		arg.Tier,
		arg.IsActive,
		arg.Notes,
	)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const updateMembershipTier = `-- name: UpdateMembershipTier :one
UPDATE membership_tiers SET name=$2, discount_type=$3, discount_value=$4, min_orders=$5, min_spend=$6, is_active=$7, updated_at=now()
WHERE id=$1 RETURNING id, code, name, discount_type, discount_value, min_orders, min_spend, is_active, created_at, updated_at
`

type UpdateMembershipTierParams struct {
	ID            int64           `json:"id"`
	Name          string          `json:"name"`
	DiscountType  string          `json:"discount_type"`
	DiscountValue decimal.Decimal `json:"discount_value"`
	MinOrders     int32           `json:"min_orders"`
	MinSpend      decimal.Decimal `json:"min_spend"`
	IsActive      bool            `json:"is_active"`
}

func (q *Queries) UpdateMembershipTier(ctx context.Context, arg UpdateMembershipTierParams) (MembershipTier, error) {
	row := q.db.QueryRow(ctx, updateMembershipTier,
		arg.ID,
		arg.Name,
		arg.DiscountType,
		arg.DiscountValue,
		arg.MinOrders,
		arg.MinSpend,
		arg.IsActive,
	)
	var i MembershipTier
	err := row.Scan(
		&i.ID,
		&i.Code,
		&i.Name,
		&i.DiscountType,
		&i.DiscountValue,
		&i.MinOrders,
		&i.MinSpend,
		&i.IsActive,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}
