package output

import (
	"fmt"

	helmMock "github.com/ocdp/cluster-service/internal/adapter/output/helm/mock"
	helmReal "github.com/ocdp/cluster-service/internal/adapter/output/helm/real"
	"github.com/ocdp/cluster-service/internal/adapter/output/k8s"
	ociMock "github.com/ocdp/cluster-service/internal/adapter/output/oci/mock"
	ociReal "github.com/ocdp/cluster-service/internal/adapter/output/oci/real"
	"github.com/ocdp/cluster-service/internal/adapter/output/persistence/mock"
	"github.com/ocdp/cluster-service/internal/adapter/output/persistence/postgres"
	"github.com/ocdp/cluster-service/internal/domain/repository"
	"github.com/ocdp/cluster-service/internal/pkg/crypto"
)

// AdapterMode 适配器模式
type AdapterMode string

const (
	ModeMock AdapterMode = "mock" // Mock 模式（内存存储，用于开发调试）
	// 默认模式：连接真实 PostgreSQL 和服务（任何非 "mock" 的值都是默认模式）
)

// AdapterFactory 适配器工厂
// 用于创建所有 Output Adapters，支持 Mock 和真实实现切换
type AdapterFactory struct {
	mode      AdapterMode
	encryptor crypto.Encryptor // 加密器（用于敏感数据加密）

	// 数据库连接字符串（非 Mock 模式需要）
	dbConnString string

	// 数据库连接（非 Mock 模式）
	db *postgres.DB
}

// NewAdapterFactory 创建适配器工厂
func NewAdapterFactory(mode AdapterMode, encryptor crypto.Encryptor, dbConnString string) *AdapterFactory {
	return &AdapterFactory{
		mode:         mode,
		encryptor:    encryptor,
		dbConnString: dbConnString,
	}
}

// CreateUserRepository 创建用户仓储
func (f *AdapterFactory) CreateUserRepository() (repository.UserRepository, error) {
	if f.mode == ModeMock {
		return mock.NewUserRepositoryMock(), nil
	}

	// 默认：真实实现（PostgreSQL）
	if err := f.ensureDBConnection(); err != nil {
		return nil, err
	}
	return postgres.NewUserRepository(f.db), nil
}

// CreateClusterRepository 创建集群仓储
func (f *AdapterFactory) CreateClusterRepository() (repository.ClusterRepository, error) {
	if f.mode == ModeMock {
		return mock.NewClusterRepositoryMock(f.encryptor), nil
	}

	// 默认：真实实现（PostgreSQL）
	if err := f.ensureDBConnection(); err != nil {
		return nil, err
	}
	return postgres.NewClusterRepository(f.db, f.encryptor), nil
}

// CreateRegistryRepository 创建 Registry 仓储
func (f *AdapterFactory) CreateRegistryRepository() (repository.RegistryRepository, error) {
	if f.mode == ModeMock {
		return mock.NewRegistryRepositoryMock(f.encryptor), nil
	}

	// 默认：真实实现（PostgreSQL）
	if err := f.ensureDBConnection(); err != nil {
		return nil, err
	}
	return postgres.NewRegistryRepository(f.db, f.encryptor), nil
}

// CreateInstanceRepository 创建实例仓储
func (f *AdapterFactory) CreateInstanceRepository() (repository.InstanceRepository, error) {
	if f.mode == ModeMock {
		return mock.NewInstanceRepositoryMock(), nil
	}

	// 默认：真实实现（PostgreSQL）
	if err := f.ensureDBConnection(); err != nil {
		return nil, err
	}
	return postgres.NewInstanceRepository(f.db), nil
}

func (f *AdapterFactory) CreateWorkspaceRepository() (repository.WorkspaceRepository, error) {
	if f.mode == ModeMock {
		return mock.NewWorkspaceRepositoryMock(), nil
	}
	if err := f.ensureDBConnection(); err != nil {
		return nil, err
	}
	return postgres.NewWorkspaceRepository(f.db), nil
}

func (f *AdapterFactory) CreateWorkspaceClusterBindingRepository() (repository.WorkspaceClusterBindingRepository, error) {
	if f.mode == ModeMock {
		return mock.NewWorkspaceClusterBindingRepositoryMock(), nil
	}
	if err := f.ensureDBConnection(); err != nil {
		return nil, err
	}
	return postgres.NewWorkspaceClusterBindingRepository(f.db), nil
}

func (f *AdapterFactory) CreateAuditLogRepository() (repository.AuditLogRepository, error) {
	if f.mode == ModeMock {
		return mock.NewAuditLogRepositoryMock(), nil
	}
	if err := f.ensureDBConnection(); err != nil {
		return nil, err
	}
	return postgres.NewAuditLogRepository(f.db), nil
}

// CreateOCIClient 创建 OCI 客户端
func (f *AdapterFactory) CreateOCIClient() (repository.OCIClient, error) {
	if f.mode == ModeMock {
		return ociMock.NewOCIClientMock(), nil
	}

	// 默认：真实实现（ORAS SDK）
	return ociReal.NewOCIClient(), nil
}

// CreateHelmClient 创建 Helm 客户端
func (f *AdapterFactory) CreateHelmClient() (repository.HelmClient, error) {
	if f.mode == ModeMock {
		return helmMock.NewHelmClientMock(), nil
	}

	// 默认：真实实现（Helm SDK）
	return helmReal.NewHelmClient(), nil
}

// CreateMetricsClient 创建 Metrics 客户端
func (f *AdapterFactory) CreateMetricsClient(clusterRepo repository.ClusterRepository) repository.MetricsClient {
	// Metrics client 总是使用真实的 Kubernetes API
	return k8s.NewMetricsClient(clusterRepo)
}

// CreateEntryClient 创建实例入口查询客户端
func (f *AdapterFactory) CreateEntryClient() repository.InstanceEntryClient {
	return k8s.NewEntryClient()
}

func (f *AdapterFactory) CreateDiagnosticsClient() repository.InstanceDiagnosticsClient {
	if f.mode == ModeMock {
		return k8s.NewMockDiagnosticsClient()
	}
	return k8s.NewDiagnosticsClient()
}

func (f *AdapterFactory) CreateTenantKubeClient() repository.TenantKubeClient {
	if f.mode == ModeMock {
		return k8s.NewMockTenantClient()
	}
	return k8s.NewTenantClient()
}

// CreateAllRepositories 一次性创建所有 Repositories
func (f *AdapterFactory) CreateAllRepositories() (*Repositories, error) {
	userRepo, err := f.CreateUserRepository()
	if err != nil {
		return nil, fmt.Errorf("failed to create user repository: %w", err)
	}

	clusterRepo, err := f.CreateClusterRepository()
	if err != nil {
		return nil, fmt.Errorf("failed to create cluster repository: %w", err)
	}

	registryRepo, err := f.CreateRegistryRepository()
	if err != nil {
		return nil, fmt.Errorf("failed to create registry repository: %w", err)
	}

	instanceRepo, err := f.CreateInstanceRepository()
	if err != nil {
		return nil, fmt.Errorf("failed to create instance repository: %w", err)
	}

	workspaceRepo, err := f.CreateWorkspaceRepository()
	if err != nil {
		return nil, fmt.Errorf("failed to create workspace repository: %w", err)
	}

	bindingRepo, err := f.CreateWorkspaceClusterBindingRepository()
	if err != nil {
		return nil, fmt.Errorf("failed to create workspace cluster binding repository: %w", err)
	}

	auditRepo, err := f.CreateAuditLogRepository()
	if err != nil {
		return nil, fmt.Errorf("failed to create audit log repository: %w", err)
	}

	ociClient, err := f.CreateOCIClient()
	if err != nil {
		return nil, fmt.Errorf("failed to create OCI client: %w", err)
	}

	helmClient, err := f.CreateHelmClient()
	if err != nil {
		return nil, fmt.Errorf("failed to create Helm client: %w", err)
	}

	// 创建 Metrics client（依赖 clusterRepo）
	metricsClient := f.CreateMetricsClient(clusterRepo)
	entryClient := f.CreateEntryClient()
	diagnosticsClient := f.CreateDiagnosticsClient()
	tenantClient := f.CreateTenantKubeClient()

	return &Repositories{
		UserRepo:          userRepo,
		WorkspaceRepo:     workspaceRepo,
		BindingRepo:       bindingRepo,
		AuditRepo:         auditRepo,
		ClusterRepo:       clusterRepo,
		RegistryRepo:      registryRepo,
		InstanceRepo:      instanceRepo,
		OCIClient:         ociClient,
		HelmClient:        helmClient,
		MetricsClient:     metricsClient,
		EntryClient:       entryClient,
		DiagnosticsClient: diagnosticsClient,
		TenantKubeClient:  tenantClient,
	}, nil
}

// Repositories 所有仓储的集合
type Repositories struct {
	UserRepo          repository.UserRepository
	WorkspaceRepo     repository.WorkspaceRepository
	BindingRepo       repository.WorkspaceClusterBindingRepository
	AuditRepo         repository.AuditLogRepository
	ClusterRepo       repository.ClusterRepository
	RegistryRepo      repository.RegistryRepository
	InstanceRepo      repository.InstanceRepository
	OCIClient         repository.OCIClient
	HelmClient        repository.HelmClient
	MetricsClient     repository.MetricsClient
	EntryClient       repository.InstanceEntryClient
	DiagnosticsClient repository.InstanceDiagnosticsClient
	TenantKubeClient  repository.TenantKubeClient
}

// ensureDBConnection 确保数据库连接已建立
func (f *AdapterFactory) ensureDBConnection() error {
	if f.db != nil {
		return nil
	}

	if f.dbConnString == "" {
		return fmt.Errorf("database connection string is required (set DATABASE_URL environment variable)")
	}

	db, err := postgres.NewDB(f.dbConnString)
	if err != nil {
		return fmt.Errorf("failed to connect to database: %w", err)
	}

	// 初始化数据库 schema
	if err := db.InitSchema(); err != nil {
		return fmt.Errorf("failed to initialize database schema: %w", err)
	}

	f.db = db
	return nil
}

// Close 关闭工厂资源
func (f *AdapterFactory) Close() error {
	if f.db != nil {
		return f.db.Close()
	}
	return nil
}
