// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
// SPDX-License-Identifier: Apache-2.0

// Package transport provides utilities for handling different transport modes
// for communication between the client and MCP server.
package transport

import (
	"github.com/stacklok/toolhive/pkg/transport/errors"
	"github.com/stacklok/toolhive/pkg/transport/types"
)

// Factory creates transports
type Factory struct{}

// NewFactory creates a new transport factory
func NewFactory() *Factory {
	return &Factory{}
}

// Option is a function that configures a transport
type Option func(types.Transport) error

// WithContainerName returns an option that sets the container name on a transport
func WithContainerName(containerName string) Option {
	return func(t types.Transport) error {
		if setter, ok := t.(interface{ setContainerName(string) }); ok {
			setter.setContainerName(containerName)
		}
		return nil
	}
}

// WithTargetURI returns an option that sets the target URI on a transport
func WithTargetURI(targetURI string) Option {
	return func(t types.Transport) error {
		if setter, ok := t.(interface{ setTargetURI(string) }); ok {
			setter.setTargetURI(targetURI)
		}
		return nil
	}
}

// Create creates a transport based on the provided configuration
func (*Factory) Create(config types.Config, opts ...Option) (types.Transport, error) {
	var tr types.Transport

	switch config.Type {
	case types.TransportTypeStdio:
		stdio := NewStdioTransport(
			config.Host, config.ProxyPort, config.Deployer, config.Debug, config.TrustProxyHeaders,
			config.PrometheusHandler, config.Middlewares...,
		)
		stdio.SetProxyMode(config.ProxyMode)
		if config.SessionStorage != nil {
			stdio.SetSessionStorage(config.SessionStorage)
		}
		tr = stdio
	case types.TransportTypeSSE:
		httpTransport := NewHTTPTransport(
			types.TransportTypeSSE,
			config.Host,
			config.ProxyPort,
			config.TargetPort,
			config.Deployer,
			config.Debug,
			config.TargetHost,
			config.AuthInfoHandler,
			config.PrometheusHandler,
			config.PrefixHandlers,
			config.EndpointPrefix,
			config.TrustProxyHeaders,
			config.Middlewares...,
		)
		httpTransport.sessionStorage = config.SessionStorage
		tr = httpTransport
	case types.TransportTypeStreamableHTTP:
		httpTransport := NewHTTPTransport(
			types.TransportTypeStreamableHTTP,
			config.Host,
			config.ProxyPort,
			config.TargetPort,
			config.Deployer,
			config.Debug,
			config.TargetHost,
			config.AuthInfoHandler,
			config.PrometheusHandler,
			config.PrefixHandlers,
			config.EndpointPrefix,
			config.TrustProxyHeaders,
			config.Middlewares...,
		)
		httpTransport.sessionStorage = config.SessionStorage
		tr = httpTransport
	case types.TransportTypeInspector:
		// HTTP transport is not implemented yet
		return nil, errors.ErrUnsupportedTransport
	default:
		return nil, errors.ErrUnsupportedTransport
	}

	// Apply options to the transport
	for _, opt := range opts {
		if err := opt(tr); err != nil {
			return nil, err
		}
	}

	return tr, nil
}
