package sqlite

import (
	"context"
	"fmt"
	"strings"
)

type RouteStickyAudit struct {
	ID             int64
	StickyKey      string
	StickyKeyType  string
	LogicalGroupID string
	PublicModel    string
	RouteID        string
	Action         string
	ExpiresAt      string
	CreatedAt      string
}

type RouteStickyAuditFilter struct {
	StickyKey      string
	StickyKeyType  string
	LogicalGroupID string
	PublicModel    string
	RouteID        string
	Action         string
	Limit          int
}

type RouteStickyAuditRepo struct {
	db execQuerier
}

func newRouteStickyAuditRepo(db execQuerier) *RouteStickyAuditRepo {
	return &RouteStickyAuditRepo{db: db}
}

func (r *RouteStickyAuditRepo) Create(ctx context.Context, row RouteStickyAudit) (int64, error) {
	row, err := normalizeRouteStickyAudit(row)
	if err != nil {
		return 0, err
	}

	result, err := r.db.ExecContext(
		ctx,
		`INSERT INTO route_sticky_audit (
			sticky_key,
			sticky_key_type,
			logical_group_id,
			public_model,
			route_id,
			action,
			expires_at
		) VALUES (?, ?, ?, ?, ?, ?, ?)`,
		row.StickyKey,
		row.StickyKeyType,
		row.LogicalGroupID,
		row.PublicModel,
		row.RouteID,
		row.Action,
		row.ExpiresAt,
	)
	if err != nil {
		return 0, fmt.Errorf("insert route sticky audit %q: %w", row.StickyKey, err)
	}

	id, err := result.LastInsertId()
	if err != nil {
		return 0, fmt.Errorf("read inserted route sticky audit id for %q: %w", row.StickyKey, err)
	}
	return id, nil
}

func (r *RouteStickyAuditRepo) ListRecent(ctx context.Context, filter RouteStickyAuditFilter) ([]RouteStickyAudit, error) {
	clauses := make([]string, 0, 6)
	args := make([]any, 0, 7)

	if stickyKey := strings.TrimSpace(filter.StickyKey); stickyKey != "" {
		clauses = append(clauses, "sticky_key = ?")
		args = append(args, stickyKey)
	}
	if stickyKeyType := strings.TrimSpace(filter.StickyKeyType); stickyKeyType != "" {
		clauses = append(clauses, "sticky_key_type = ?")
		args = append(args, stickyKeyType)
	}
	if logicalGroupID := strings.TrimSpace(filter.LogicalGroupID); logicalGroupID != "" {
		clauses = append(clauses, "logical_group_id = ?")
		args = append(args, logicalGroupID)
	}
	if publicModel := strings.TrimSpace(filter.PublicModel); publicModel != "" {
		clauses = append(clauses, "public_model = ?")
		args = append(args, publicModel)
	}
	if routeID := strings.TrimSpace(filter.RouteID); routeID != "" {
		clauses = append(clauses, "route_id = ?")
		args = append(args, routeID)
	}
	if action := strings.TrimSpace(filter.Action); action != "" {
		clauses = append(clauses, "action = ?")
		args = append(args, action)
	}

	query := `SELECT id, sticky_key, sticky_key_type, logical_group_id, public_model, route_id, action, expires_at, created_at
		FROM route_sticky_audit`
	if len(clauses) > 0 {
		query += " WHERE " + strings.Join(clauses, " AND ")
	}
	query += " ORDER BY id DESC LIMIT ?"
	args = append(args, normalizeRouteLogListLimit(filter.Limit))

	rows, err := r.db.QueryContext(ctx, query, args...)
	if err != nil {
		return nil, fmt.Errorf("list route sticky audit: %w", err)
	}
	defer rows.Close()

	items := make([]RouteStickyAudit, 0)
	for rows.Next() {
		var item RouteStickyAudit
		if err := rows.Scan(
			&item.ID,
			&item.StickyKey,
			&item.StickyKeyType,
			&item.LogicalGroupID,
			&item.PublicModel,
			&item.RouteID,
			&item.Action,
			&item.ExpiresAt,
			&item.CreatedAt,
		); err != nil {
			return nil, fmt.Errorf("scan route sticky audit: %w", err)
		}
		items = append(items, item)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("iterate route sticky audit: %w", err)
	}
	return items, nil
}

func normalizeRouteStickyAudit(row RouteStickyAudit) (RouteStickyAudit, error) {
	row.StickyKey = strings.TrimSpace(row.StickyKey)
	row.StickyKeyType = strings.TrimSpace(row.StickyKeyType)
	row.LogicalGroupID = strings.TrimSpace(row.LogicalGroupID)
	row.PublicModel = strings.TrimSpace(row.PublicModel)
	row.RouteID = strings.TrimSpace(row.RouteID)
	row.Action = strings.TrimSpace(row.Action)
	row.ExpiresAt = strings.TrimSpace(row.ExpiresAt)

	switch {
	case row.StickyKey == "":
		return RouteStickyAudit{}, fmt.Errorf("sticky_key is required")
	case row.StickyKeyType == "":
		return RouteStickyAudit{}, fmt.Errorf("sticky_key_type is required")
	case row.LogicalGroupID == "":
		return RouteStickyAudit{}, fmt.Errorf("logical_group_id is required")
	case row.PublicModel == "":
		return RouteStickyAudit{}, fmt.Errorf("public_model is required")
	case row.RouteID == "":
		return RouteStickyAudit{}, fmt.Errorf("route_id is required")
	case row.Action == "":
		return RouteStickyAudit{}, fmt.Errorf("action is required")
	}

	return row, nil
}
