package virtualtables

import (
	"context"
	"fmt"

	"github.com/everything-on-mysql/cassandra-on-mysql/pkg/cql/keyspace"
	"github.com/everything-on-mysql/cassandra-on-mysql/pkg/cql/parser"
	"github.com/everything-on-mysql/cassandra-on-mysql/pkg/cql/types"
)

// VirtualTableExecutor handles execution of queries against virtual tables
type VirtualTableExecutor struct {
	registry *Registry
}

// NewVirtualTableExecutor creates a new virtual table executor
func NewVirtualTableExecutor(registry *Registry) *VirtualTableExecutor {
	return &VirtualTableExecutor{
		registry: registry,
	}
}

// LookupTable exposes the virtual table definition for describe-style queries.
func (v *VirtualTableExecutor) LookupTable(name string) (*VirtualTable, bool) {
	if v == nil || v.registry == nil {
		return nil, false
	}
	return v.registry.Lookup(name)
}

// IsVirtualTableQuery checks if a query targets a virtual table
func IsVirtualTableQuery(stmt *parser.SelectStatement) bool {
	if stmt == nil || stmt.From == nil {
		return false
	}
	if stmt.From.Schema == "" {
		return false
	}
	return keyspace.IsVirtual(stmt.From.Schema)
}

// Execute executes a query against a virtual table
func (v *VirtualTableExecutor) Execute(ctx context.Context, stmt *parser.SelectStatement, user string) (*types.QueryResult, error) {
	if stmt == nil || stmt.From == nil {
		return nil, fmt.Errorf("invalid statement")
	}

	keyspaceName := stmt.From.Schema
	tableName := stmt.From.Name
	if keyspaceName == "" || tableName == "" {
		return nil, fmt.Errorf("invalid virtual table reference: %s", stmt.From.String())
	}

	// Handle schema queries (system_virtual_schema)
	if keyspaceName == "system_virtual_schema" {
		return v.executeSchemaQuery(ctx, stmt)
	}

	// Handle data queries (virtual keyspaces other than system_virtual_schema)
	if keyspaceName == "system_views" ||
		keyspaceName == "system_metrics" ||
		keyspaceName == "system_accord_debug" ||
		keyspaceName == "system_accord_debug_remote" {
		return v.executeDataQuery(ctx, stmt, user)
	}

	return nil, fmt.Errorf("unknown virtual table keyspace: %s", keyspaceName)
}

// executeDataQuery executes queries against system_views tables
func (v *VirtualTableExecutor) executeDataQuery(ctx context.Context, stmt *parser.SelectStatement, user string) (*types.QueryResult, error) {
	keyspaceName := stmt.From.Schema
	tableName := stmt.From.Name
	if keyspaceName == "" || tableName == "" {
		return nil, fmt.Errorf("invalid virtual table reference: %s", stmt.From.String())
	}

	// Build full name
	fullName := fmt.Sprintf("%s.%s", keyspaceName, tableName)

	// Lookup virtual table
	vt, ok := v.registry.Lookup(fullName)
	if !ok {
		return nil, fmt.Errorf("virtual table not found: %s", fullName)
	}

	// Extract options from statement
	opts := QueryOptions{
		WhereClause: stmt.Where,
	}

	// Extract LIMIT if present
	if stmt.Options.Limit != nil {
		// Limit is an Expression, need to extract value
		if lit, ok := stmt.Options.Limit.(*parser.IntegerLiteral); ok {
			limit := lit.Value
			opts.Limit = &limit
		}
	}
	if stmt.Options.Offset != nil {
		if lit, ok := stmt.Options.Offset.(*parser.IntegerLiteral); ok {
			offset := lit.Value
			opts.Offset = &offset
		}
	}

	// Call provider to get data
	rows, err := vt.Provider(ctx, opts)
	if err != nil {
		return nil, fmt.Errorf("failed to get data: %w", err)
	}

	// Apply WHERE filtering if present
	if stmt.Where != nil {
		filter := NewFilterEngine(stmt.Where)
		filtered := make([]types.Row, 0)
		for _, row := range rows {
			match, err := filter.Evaluate(row, vt.Columns)
			if err != nil {
				return nil, fmt.Errorf("filter evaluation error: %w", err)
			}
			if match {
				filtered = append(filtered, row)
			}
		}
		rows = filtered
	}

	// Apply OFFSET if present
	if opts.Offset != nil && *opts.Offset > 0 {
		if int64(len(rows)) <= *opts.Offset {
			rows = nil
		} else {
			rows = rows[*opts.Offset:]
		}
	}

	// Apply LIMIT if present
	if opts.Limit != nil && int64(len(rows)) > *opts.Limit {
		rows = rows[:*opts.Limit]
	}

	// Build result
	result := &types.QueryResult{
		Columns: vt.Columns,
		Rows:    rows,
	}

	return result, nil
}

// executeSchemaQuery executes queries against system_virtual_schema tables
func (v *VirtualTableExecutor) executeSchemaQuery(ctx context.Context, stmt *parser.SelectStatement) (*types.QueryResult, error) {
	tableName := stmt.From.Name
	if tableName == "" {
		return nil, fmt.Errorf("invalid virtual schema reference: %s", stmt.From.String())
	}

	var result *types.QueryResult
	var err error

	switch tableName {
	case "keyspaces":
		result, err = getKeyspaceSchema(v.registry)
	case "tables":
		result, err = getTableSchema(v.registry)
	case "columns":
		result, err = getColumnSchema(v.registry)
	default:
		return nil, fmt.Errorf("unknown virtual schema table: %s", tableName)
	}

	if err != nil {
		return nil, err
	}

	// Apply WHERE filtering if present
	if stmt.Where != nil {
		filter := NewFilterEngine(stmt.Where)
		filtered := make([]types.Row, 0)
		for _, row := range result.Rows {
			match, err := filter.Evaluate(row, result.Columns)
			if err != nil {
				return nil, fmt.Errorf("filter evaluation error: %w", err)
			}
			if match {
				filtered = append(filtered, row)
			}
		}
		result.Rows = filtered
	}

	// Apply LIMIT if present
	if stmt.Options.Limit != nil {
		if lit, ok := stmt.Options.Limit.(*parser.IntegerLiteral); ok {
			limit := lit.Value
			if len(result.Rows) > int(limit) {
				result.Rows = result.Rows[:limit]
			}
		}
	}

	return result, nil
}
