package app import ( "tercul/internal/app/auth" "tercul/internal/app/copyright" "tercul/internal/app/localization" "tercul/internal/app/search" "tercul/internal/app/work" "tercul/internal/data/sql" "tercul/internal/domain" "tercul/internal/platform/cache" "tercul/internal/platform/config" "tercul/internal/platform/db" "tercul/internal/platform/log" auth_platform "tercul/internal/platform/auth" "tercul/internal/jobs/linguistics" "time" "github.com/hibiken/asynq" "github.com/weaviate/weaviate-go-client/v5/weaviate" "gorm.io/gorm" ) // ApplicationBuilder handles the initialization of all application components type ApplicationBuilder struct { dbConn *gorm.DB redisCache cache.Cache weaviateClient *weaviate.Client asynqClient *asynq.Client App *Application linguistics *linguistics.LinguisticsFactory } // NewApplicationBuilder creates a new ApplicationBuilder func NewApplicationBuilder() *ApplicationBuilder { return &ApplicationBuilder{} } // BuildDatabase initializes the database connection func (b *ApplicationBuilder) BuildDatabase() error { log.LogInfo("Initializing database connection") dbConn, err := db.InitDB() if err != nil { log.LogFatal("Failed to initialize database", log.F("error", err)) return err } b.dbConn = dbConn log.LogInfo("Database initialized successfully") return nil } // BuildCache initializes the Redis cache func (b *ApplicationBuilder) BuildCache() error { log.LogInfo("Initializing Redis cache") redisCache, err := cache.NewDefaultRedisCache() if err != nil { log.LogWarn("Failed to initialize Redis cache, continuing without caching", log.F("error", err)) } else { b.redisCache = redisCache log.LogInfo("Redis cache initialized successfully") } return nil } // BuildWeaviate initializes the Weaviate client func (b *ApplicationBuilder) BuildWeaviate() error { log.LogInfo("Connecting to Weaviate", log.F("host", config.Cfg.WeaviateHost)) wClient, err := weaviate.NewClient(weaviate.Config{ Scheme: config.Cfg.WeaviateScheme, Host: config.Cfg.WeaviateHost, }) if err != nil { log.LogFatal("Failed to create Weaviate client", log.F("error", err)) return err } b.weaviateClient = wClient log.LogInfo("Weaviate client initialized successfully") return nil } // BuildBackgroundJobs initializes Asynq for background job processing func (b *ApplicationBuilder) BuildBackgroundJobs() error { log.LogInfo("Setting up background job processing") redisOpt := asynq.RedisClientOpt{ Addr: config.Cfg.RedisAddr, Password: config.Cfg.RedisPassword, DB: config.Cfg.RedisDB, } b.asynqClient = asynq.NewClient(redisOpt) log.LogInfo("Background job client initialized successfully") return nil } // BuildLinguistics initializes the linguistics components func (b *ApplicationBuilder) BuildLinguistics() error { log.LogInfo("Initializing linguistic analyzer") b.linguistics = linguistics.NewLinguisticsFactory(b.dbConn, b.redisCache, 4, true) log.LogInfo("Linguistics components initialized successfully") return nil } // BuildApplication initializes all application services func (b *ApplicationBuilder) BuildApplication() error { log.LogInfo("Initializing application layer") // Initialize repositories // Note: This is a simplified wiring. In a real app, you might have more complex dependencies. workRepo := sql.NewWorkRepository(b.dbConn) userRepo := sql.NewUserRepository(b.dbConn) // I need to add all the other repos here. For now, I'll just add the ones I need for the services. translationRepo := sql.NewTranslationRepository(b.dbConn) copyrightRepo := sql.NewCopyrightRepository(b.dbConn) // Initialize application services workCommands := work.NewWorkCommands(workRepo, b.linguistics.GetAnalyzer()) workQueries := work.NewWorkQueries(workRepo) jwtManager := auth_platform.NewJWTManager() authCommands := auth.NewAuthCommands(userRepo, jwtManager) authQueries := auth.NewAuthQueries(userRepo, jwtManager) copyrightCommands := copyright.NewCopyrightCommands(copyrightRepo) copyrightQueries := copyright.NewCopyrightQueries(copyrightRepo) localizationService := localization.NewService(translationRepo) searchService := search.NewIndexService(localizationService, translationRepo) b.App = &Application{ WorkCommands: workCommands, WorkQueries: workQueries, AuthCommands: authCommands, AuthQueries: authQueries, CopyrightCommands: copyrightCommands, CopyrightQueries: copyrightQueries, Localization: localizationService, Search: searchService, } log.LogInfo("Application layer initialized successfully") return nil } // Build initializes all components in the correct order func (b *ApplicationBuilder) Build() error { if err := b.BuildDatabase(); err != nil { return err } if err := b.BuildCache(); err != nil { return err } if err := b.BuildWeaviate(); err != nil { return err } if err := b.BuildBackgroundJobs(); err != nil { return err } if err := b.BuildLinguistics(); err != nil { return err } if err := b.BuildApplication(); err != nil { return err } log.LogInfo("Application builder completed successfully") return nil } // GetApplication returns the application container func (b *ApplicationBuilder) GetApplication() *Application { return b.App } // Close closes all resources func (b *ApplicationBuilder) Close() error { if b.asynqClient != nil { b.asynqClient.Close() } if b.dbConn != nil { sqlDB, err := b.dbConn.DB() if err == nil { sqlDB.Close() } } return nil }