package systemtables

import (
	"fmt"
	"strings"

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

// SchemaIntrospector provides schema information for system tables
type SchemaIntrospector struct {
	registry *Registry
}

// NewSchemaIntrospector creates a new schema introspector
func NewSchemaIntrospector(registry *Registry) *SchemaIntrospector {
	return &SchemaIntrospector{
		registry: registry,
	}
}

// GetKeyspaceSchema returns all tables in a keyspace
func (s *SchemaIntrospector) GetKeyspaceSchema(keyspace string) ([]types.Row, error) {
	tables := s.registry.ListAll()
	var result []types.Row

	for _, table := range tables {
		if table.Keyspace == keyspace {
			result = append(result, types.Row{
				Values: []interface{}{
					table.Keyspace,
					table.Table,
					table.Comment,
				},
			})
		}
	}

	return result, nil
}

// GetTableSchema returns detailed schema for a specific table
func (s *SchemaIntrospector) GetTableSchema(keyspace, table string) ([]types.ColumnInfo, error) {
	fullName := fmt.Sprintf("%s.%s", keyspace, table)
	st, ok := s.registry.Lookup(fullName)
	if !ok {
		return nil, fmt.Errorf("table not found: %s", fullName)
	}
	return st.Columns, nil
}

// GetColumnSchema returns schema for all columns in a table
func (s *SchemaIntrospector) GetColumnSchema(keyspace, table string) ([]types.Row, error) {
	fullName := fmt.Sprintf("%s.%s", keyspace, table)
	st, ok := s.registry.Lookup(fullName)
	if !ok {
		return nil, fmt.Errorf("table not found: %s", fullName)
	}

	var result []types.Row
	for _, col := range st.Columns {
		kind, _, _ := columnKind(st, col.Name)
		result = append(result, types.Row{
			Values: []interface{}{
				keyspace,
				table,
				col.Name,
				kind,
				col.Type,
			},
		})
	}

	return result, nil
}

// IsSystemKeyspace checks if a keyspace name is a system keyspace
func IsSystemKeyspace(name string) bool {
	return keyspace.IsSystem(name)
}

// GetSystemKeyspaces returns all system keyspaces
func (s *SchemaIntrospector) GetSystemKeyspaces() []string {
	tables := s.registry.ListAll()
	seen := make(map[string]bool)
	var keyspaces []string

	for _, table := range tables {
		if !seen[table.Keyspace] {
			keyspaces = append(keyspaces, table.Keyspace)
			seen[table.Keyspace] = true
		}
	}

	return keyspaces
}

// GetTableColumns returns just the column names for a table
func (s *SchemaIntrospector) GetTableColumns(keyspace, table string) ([]string, error) {
	fullName := fmt.Sprintf("%s.%s", keyspace, table)
	st, ok := s.registry.Lookup(fullName)
	if !ok {
		return nil, fmt.Errorf("table not found: %s", fullName)
	}

	columns := make([]string, len(st.Columns))
	for i, col := range st.Columns {
		columns[i] = col.Name
	}

	return columns, nil
}

// GetColumnType returns the type of a specific column
func (s *SchemaIntrospector) GetColumnType(keyspace, table, column string) (string, error) {
	fullName := fmt.Sprintf("%s.%s", keyspace, table)
	st, ok := s.registry.Lookup(fullName)
	if !ok {
		return "", fmt.Errorf("table not found: %s", fullName)
	}

	for _, col := range st.Columns {
		if col.Name == column {
			return col.Type, nil
		}
	}

	return "", fmt.Errorf("column not found: %s.%s.%s", keyspace, table, column)
}

// ValidateTableExists checks if a table exists
func (s *SchemaIntrospector) ValidateTableExists(keyspace, table string) bool {
	fullName := fmt.Sprintf("%s.%s", keyspace, table)
	_, ok := s.registry.Lookup(fullName)
	return ok
}

// GetTableComment returns the comment for a table
func (s *SchemaIntrospector) GetTableComment(keyspace, table string) (string, error) {
	fullName := fmt.Sprintf("%s.%s", keyspace, table)
	st, ok := s.registry.Lookup(fullName)
	if !ok {
		return "", fmt.Errorf("table not found: %s", fullName)
	}
	return st.Comment, nil
}

// IsReadOnlyTable checks if a table is read-only
func (s *SchemaIntrospector) IsReadOnlyTable(keyspace, table string) (bool, error) {
	fullName := fmt.Sprintf("%s.%s", keyspace, table)
	st, ok := s.registry.Lookup(fullName)
	if !ok {
		return false, fmt.Errorf("table not found: %s", fullName)
	}
	return st.IsReadOnly, nil
}

// GetSupportedOperations returns the supported operations for a table
func (s *SchemaIntrospector) GetSupportedOperations(keyspace, table string) ([]string, error) {
	fullName := fmt.Sprintf("%s.%s", keyspace, table)
	st, ok := s.registry.Lookup(fullName)
	if !ok {
		return nil, fmt.Errorf("table not found: %s", fullName)
	}

	operations := []string{"SELECT"}
	if !st.IsReadOnly {
		operations = append(operations, "INSERT", "UPDATE", "DELETE")
	}

	return operations, nil
}

// GetTableType returns the type of table (system, virtual, etc.)
func (s *SchemaIntrospector) GetTableType(keyspace, table string) (string, error) {
	fullName := fmt.Sprintf("%s.%s", keyspace, table)
	st, ok := s.registry.Lookup(fullName)
	if !ok {
		return "", fmt.Errorf("table not found: %s", fullName)
	}

	if strings.HasPrefix(st.Name, "system_views.") {
		return "virtual", nil
	}
	if strings.HasPrefix(st.Name, "system_virtual_schema.") {
		return "virtual_schema", nil
	}
	if strings.HasPrefix(st.Name, "system.") {
		return "system", nil
	}
	if strings.HasPrefix(st.Name, "system_schema.") {
		return "system_schema", nil
	}
	if strings.HasPrefix(st.Name, "system_distributed.") {
		return "system_distributed", nil
	}
	if strings.HasPrefix(st.Name, "system_auth.") {
		return "system_auth", nil
	}
	if strings.HasPrefix(st.Name, "system_traces.") {
		return "system_traces", nil
	}
	if strings.HasPrefix(st.Name, "system_cluster_metadata.") {
		return "system_cluster_metadata", nil
	}
	if strings.HasPrefix(st.Name, "system_accord.") {
		return "system_accord", nil
	}
	if strings.HasPrefix(st.Name, "dse_security.") {
		return "dse_security", nil
	}

	return "unknown", nil
}

// BuildSchemaQueryResult builds a query result for schema introspection queries
func (s *SchemaIntrospector) BuildSchemaQueryResult(keyspace, table string, queryType string) ([]types.Row, error) {
	switch queryType {
	case "keyspaces":
		return s.GetKeyspaceSchema(keyspace)
	case "tables":
		// Return all tables in the keyspace with their metadata
		tables := s.registry.ListAll()
		var result []types.Row
		for _, t := range tables {
			if t.Keyspace == keyspace {
				result = append(result, types.Row{
					Values: []interface{}{
						t.Keyspace,
						t.Table,
						0.01,                             // bloom_filter_fp_chance
						map[string]string{"keys": "ALL"}, // caching
						t.Comment,
						map[string]string{"class": "LeveledCompactionStrategy"}, // compaction
						map[string]string{"class": "LZ4Compressor"},             // compression
						1.0,                                    // crc_check_chance
						0,                                      // default_time_to_live
						map[string]string{},                    // extensions
						[]string{"virtual"},                    // flags
						86400,                                  // gc_grace_seconds
						"00000000-0000-0000-0000-000000000001", // id
						2048,                                   // max_index_interval
						0,                                      // memtable_flush_period_in_ms
						50,                                     // min_index_interval
						"ALWAYS",                               // speculative_retry
					},
				})
			}
		}
		return result, nil
	case "columns":
		return s.GetColumnSchema(keyspace, table)
	default:
		return nil, fmt.Errorf("unknown schema query type: %s", queryType)
	}
}
