package ontology

import (
	"fmt"

	"github.com/rafflesia-ai/bijection/internal/connectorcontract"
)

// virtualTableValue binds a Source to an external relation. It owns no rows,

func VirtualDialect(kind string) string {
	switch kind {
	case "postgres", "supabase":
		return "postgres"
	case "bigquery":
		return "bigquery"
	case "snowflake":
		return "snowflake"
	case "sqlserver":
		return "sqlserver"
	default:
		return ""
	}
}

func validateVirtualDataset(d DatasetSpec, connection *ConnectionSpec) error {
	if !d.IsVirtual {
		return nil
	}
	if connection == nil || VirtualDialect(connection.Kind) == "" && !(connectorcontract.SupportsObjectManifest(connection.Kind) && (d.ObjectManifest || d.IcebergSnapshot)) {
		return fmt.Errorf("virtual table %s requires a qualified SQL endpoint or pinned Parquet/Iceberg object source", d.Name)
	}
	if !d.Capture.IsDefault() || d.Cadence != 0 || d.Exportable || len(d.Parameters) != 0 {
		return fmt.Errorf("virtual table %s cannot declare capture, cadence, export, file resources or read parameters", d.Name)
	}
	if connection.RefreshDataset == d.Name {
		return fmt.Errorf("virtual table %s cannot be a capture refresh target", d.Name)
	}
	for _, c := range d.Columns {
		if c.Source != "" || c.Convert != "" {
			return fmt.Errorf("virtual table %s column %s: declare physical column names; transformations belong in Requel", d.Name, c.Name)
		}
	}
	return nil
}

// VirtualConnection returns the one external execution context for the entire
// relation set. Mixing physical stores is an explicit unsupported plan, never
// a reason to scan or materialize another source implicitly.
func (r *Registry) VirtualConnection(datasets []string) (*ConnectionSpec, bool, error) {
	var selected *ConnectionSpec
	var captured bool
	for _, name := range datasets {
		d, ok := r.Dataset(name)
		if !ok {
			return nil, false, fmt.Errorf("source dataset %s does not exist", name)
		}
		if !d.IsVirtual {
			captured = true
			continue
		}
		connection, ok := r.Connection(d.Connection)
		if !ok {
			return nil, true, fmt.Errorf("virtual source connection is unavailable")
		}
		if selected != nil && selected.Name != connection.Name {
			return nil, true, BadRequest("cross-source virtual queries are unsupported")
		}
		selected = connection
	}
	if selected != nil && captured {
		return nil, true, BadRequest("joining captured and virtual sources is unsupported")
	}
	return selected, selected != nil, nil
}

// CapturedSourceDatasets is the capture publication inventory. A virtual
// Source has no capture version and cannot block on one becoming available.
func (r *Registry) CapturedSourceDatasets() []*DatasetSpec {
	var result []*DatasetSpec
	for _, dataset := range r.SourceDatasets() {
		if !dataset.IsVirtual {
			result = append(result, dataset)
		}
	}
	return result
}

// VirtualFunctionSources identifies a Function that requires external routing.
// Unlike an Action's keyed decision read, Function terminals may use independent
// connections. Placement remains declaration-owned and is proved per terminal.
func (r *Registry) VirtualFunctionSources(datasets []string) (*ConnectionSpec, bool, error) {
	var selected *ConnectionSpec
	for _, name := range datasets {
		d, ok := r.Dataset(name)
		if !ok {
			return nil, false, fmt.Errorf("source dataset %s does not exist", name)
		}
		if d.IsVirtual {
			selected, _ = r.Connection(d.Connection)
		}
	}
	return selected, selected != nil, nil
}
