package query

import (
	"fmt"
	"strings"
)

// Join adds a JOIN clause
func (b *Builder) Join(joinType string, table string, alias string, on string) *Builder {
	if b.queryType != QueryTypeSelect {
		return b
	}

	b.joins = append(b.joins, fmt.Sprintf("%s `%s` as `%s` ON %s", joinType, table, alias, on))
	return b
}

// JoinWithParams adds a JOIN clause with bound parameters for ? placeholders in the ON condition.
// Join params are stored separately and rendered in join order before WHERE params.
func (b *Builder) JoinWithParams(joinType string, table string, alias string, on string, params []interface{}) *Builder {
	if b.queryType != QueryTypeSelect {
		return b
	}
	b.joins = append(b.joins, fmt.Sprintf("%s `%s` as `%s` ON %s", joinType, table, alias, on))
	b.joinParams = append(b.joinParams, params...)
	return b
}

// JoinFilteredWithParams joins a table after filtering it in a derived query.
// It is used when the filter contains a subquery that TiDB does not permit
// directly in a JOIN ON condition. Parameters belong to the derived filter and
// therefore precede parameters from later WHERE clauses.
func (b *Builder) JoinFilteredWithParams(joinType string, table string, filterAlias string, alias string, filter string, on string, params []interface{}) *Builder {
	if b.queryType != QueryTypeSelect {
		return b
	}
	b.joins = append(b.joins, fmt.Sprintf(
		"%s (SELECT * FROM `%s` AS `%s` WHERE %s) AS `%s` ON %s",
		joinType,
		table,
		filterAlias,
		filter,
		alias,
		on,
	))
	b.joinParams = append(b.joinParams, params...)
	return b
}

// JoinOn adds a JOIN clause with automatic aliasing for the ON condition
func (b *Builder) JoinOn(joinType string, table string, alias string, left string, op string, right string) *Builder {
	if b.queryType != QueryTypeSelect {
		return b
	}

	// Helper to resolve "a.field" or "field"
	resolve := func(in string) string {
		parts := strings.Split(in, ".")
		if len(parts) == 2 {
			// alias.field -> keep alias, resolve field
			// Note: We don't check if alias matches b.table because aliases are arbitrary
			return parts[0] + "." + b.resolveColumnName(parts[1])
		}
		// field -> resolve directly
		return b.resolveColumnName(in)
	}

	leftResolved := resolve(left)
	rightResolved := resolve(right)

	onClause := fmt.Sprintf("%s %s %s", leftResolved, op, rightResolved)
	b.joins = append(b.joins, fmt.Sprintf("%s `%s` as `%s` ON %s", joinType, table, alias, onClause))
	return b
}
