package sqls

import (
	"fmt"
	"strings"
)

const statementsNAValue = "N/A"

func isStatementsNAValue(s string) bool {
	return strings.EqualFold(strings.TrimSpace(s), statementsNAValue)
}

// statementsDisplayString maps persisted empty strings to N/A for API responses.
func statementsDisplayString(s string) string {
	if s == "" {
		return statementsNAValue
	}
	return s
}

// normalizeStatementsFilterValues trims values and maps N/A to empty string for SQL filtering.
// Plain empty query params are dropped; explicit N/A is kept as "".
func normalizeStatementsFilterValues(values []string) []string {
	out := make([]string, 0, len(values))
	for _, v := range values {
		trimmed := strings.TrimSpace(v)
		if trimmed == "" {
			continue
		}
		if isStatementsNAValue(trimmed) {
			out = append(out, "")
			continue
		}
		out = append(out, trimmed)
	}
	return out
}

func appendStatementsSchemaNameQueryFilter(filter, schemaName, dataSource string) string {
	schemaName = strings.TrimSpace(schemaName)
	if schemaName == "" {
		return filter
	}
	col := statementsDBNameColumn(dataSource)
	if isStatementsNAValue(schemaName) {
		return filter + fmt.Sprintf(" and coalesce(%s, '') = ''", col)
	}
	escaped := escapeSQLLiteral(schemaName)
	return filter + fmt.Sprintf(" and coalesce(%s, '') like '%%%s%%'", col, escaped)
}

func appendStatementsPlanDigestFilter(filter string, plans []string) string {
	if len(plans) == 0 {
		return filter
	}
	return appendStatementsCoalescedInFilter(filter, "plan_digest", plans)
}

func statementsPlanDigestGroupByClause() string {
	return "digest, coalesce(plan_digest, '')"
}

func statementsPlanDigestSelectExpr() string {
	return "coalesce(any_value(plan_digest), '') as plan_digest"
}

func replaceStatementsPlanDigestSelectExpr(fields []string) []string {
	for i, field := range fields {
		if strings.HasSuffix(field, " as plan_digest") {
			fields[i] = statementsPlanDigestSelectExpr()
			break
		}
	}
	return fields
}

func appendStatementsCoalescedInFilter(filter, colExpr string, values []string) string {
	if len(values) == 0 {
		return filter
	}

	var clauses []string
	hasEmpty := false
	nonEmpty := make([]string, 0, len(values))
	for _, v := range values {
		if v == "" {
			hasEmpty = true
			continue
		}
		nonEmpty = append(nonEmpty, v)
	}
	if hasEmpty {
		clauses = append(clauses, fmt.Sprintf("coalesce(%s, '') = ''", colExpr))
	}
	if len(nonEmpty) > 0 {
		clauses = append(clauses, fmt.Sprintf("coalesce(%s, '') in (%s)", colExpr, quoteSQLStringList(nonEmpty)))
	}
	if len(clauses) == 1 {
		return filter + " and (" + clauses[0] + ")"
	}
	return filter + " and (" + strings.Join(clauses, " or ") + ")"
}

func formatStatementsSummaryItemForAPI(item *StatementsSummaryItem, dataSource string) {
	if !isSQLsDataSourceV2(dataSource) || item.IsOther {
		return
	}
	switch item.Dimension {
	case "user":
		item.User = statementsDisplayString(item.User)
	case "sqltypes":
		item.StmtType = statementsDisplayString(item.StmtType)
	case "db":
		item.DB = statementsDisplayString(item.DB)
	case "table":
		item.Table = statementsDisplayString(item.Table)
	default:
		item.SQLDigest = statementsDisplayString(item.SQLDigest)
		item.SQLText = statementsDisplayString(item.SQLText)
	}
}

func formatStatementsTopStatsItemForAPI(item *StatementsTopStatsItem, dataSource string) {
	if !isSQLsDataSourceV2(dataSource) {
		return
	}
	item.Key = statementsDisplayString(item.Key)
	item.User = statementsDisplayString(item.User)
	item.StmtType = statementsDisplayString(item.StmtType)
	item.DB = statementsDisplayString(item.DB)
	item.Table = statementsDisplayString(item.Table)
	item.SQLDigest = statementsDisplayString(item.SQLDigest)
	item.DigestText = statementsDisplayString(item.DigestText)
	item.QuerySampleText = statementsDisplayString(item.QuerySampleText)
}

// formatStatementsListRowsForAPI maps empty string fields to N/A for v2 responses only.
func formatStatementsListRowsForAPI(rows []map[string]interface{}, dataSource string) {
	if !isSQLsDataSourceV2(dataSource) {
		return
	}
	for _, row := range rows {
		for k, v := range row {
			if s, ok := v.(string); ok && s == "" {
				row[k] = statementsNAValue
			}
		}
	}
}
