package main

import (
	"context"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"service/internal/infrastructure/cache"
	"service/internal/infrastructure/config"
	"service/internal/infrastructure/database"
	httpServer "service/internal/infrastructure/transport/http/servers"
	satuSehatFactory "service/internal/interfaces/satusehat"
	"service/pkg/logger"

	satuSehatAuth "service/internal/satusehat/reference/auth"
	satuSehatKfa "service/internal/satusehat/reference/kfa"
	satuSehatLocation "service/internal/satusehat/reference/location"
	satuSehatOrganization "service/internal/satusehat/reference/organization"
	satuSehatPatient "service/internal/satusehat/reference/patient"
	satuSehatPractitioner "service/internal/satusehat/reference/practitioner"
	satuSehatCondition "service/internal/satusehat/usecase/condition"
	satuSehatEncounter "service/internal/satusehat/usecase/encounter"
	satuSehatProcedure "service/internal/satusehat/usecase/procedure"

	_ "service/docs/swagger" // Import swagger docs

	"golang.org/x/sync/errgroup"
)

func main() {
	// 1. Load Config
	cfg := config.LoadConfig()

	// 2. Init Logger khusus untuk service Satu Sehat
	loggerConfig := logger.Config{
		Level:        cfg.Logger.Level,
		Format:       cfg.Logger.Format,
		Output:       "both",
		ServiceName:  "service-satusehat", // Penanda log
		EnableCaller: cfg.Server.Mode != "production",
		Environment:  cfg.Server.Mode,
	}
	logger.Init(loggerConfig)

	logger.Default().Info("SatuSehat Microservice starting...",
		logger.String("environment", cfg.Server.Mode),
		logger.String("log_level", cfg.Logger.Level),
	)

	if err := cfg.Validate(); err != nil {
		logger.Default().Fatal("Config validation failed", logger.ErrorField(err))
	}

	// 3. Init Database Manager
	dbService := database.New(cfg)
	defer dbService.Close()

	gormDB, err := dbService.GetGormDB("default")
	if err != nil {
		logger.Default().Fatal("Failed to get primary database", logger.ErrorField(err))
	}

	// 4. Init Cache
	cacheFactory := cache.NewFactory(cfg.Cache)
	cacheManager, err := cacheFactory.CreateManager()
	if err != nil {
		logger.Default().Fatal("Failed to initialize cache manager", logger.ErrorField(err))
	}
	defer cacheManager.Close()

	// 5. Init Layers (Hanya Modul Satu Sehat)
	satusehatFact := satuSehatFactory.NewSatuSehatFactory(cfg.SatuSehat)
	satusehatClient := satusehatFact.Client()

	// - Reference Services
	satuSehatAuthSvc := satuSehatAuth.NewService(satusehatClient, cacheManager)
	satuSehatPatientSvc := satuSehatPatient.NewService(satuSehatPatient.NewRepository(satusehatClient))
	satuSehatPractitionerSvc := satuSehatPractitioner.NewService(satuSehatPractitioner.NewRepository(satusehatClient))
	satuSehatOrganizationSvc := satuSehatOrganization.NewService(satuSehatOrganization.NewRepository(satusehatClient))
	satuSehatLocationSvc := satuSehatLocation.NewService(satuSehatLocation.NewRepository(satusehatClient))
	satuSehatKfaSvc := satuSehatKfa.NewService(satuSehatKfa.NewRepository(satusehatClient))

	// - Usecase Services
	satuSehatEncounterSvc := satuSehatEncounter.NewService(satuSehatEncounter.NewRepository(satusehatClient, dbService))
	satuSehatProcedureSvc := satuSehatProcedure.NewService(satuSehatProcedure.NewRepository(satusehatClient))
	satuSehatConditionSvc := satuSehatCondition.NewService(satuSehatCondition.NewRepository(satusehatClient))

	// 6. Server Orchestration
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	g, ctx := errgroup.WithContext(ctx)

	// --- Start REST Server (Hanya me-load endpoint Satu Sehat & Health) ---
	if cfg.Server.REST.Enabled {
		registry := &httpServer.ServiceRegistry{
			Config:       cfg,
			DBManager:    dbService,
			PrimaryDB:    gormDB,
			CacheManager: cacheManager,
			SatuSehat: &httpServer.SatuSehatServices{
				Auth:         satuSehatAuthSvc,
				Patient:      satuSehatPatientSvc,
				Practitioner: satuSehatPractitionerSvc,
				Organization: satuSehatOrganizationSvc,
				Location:     satuSehatLocationSvc,
				KFA:          satuSehatKfaSvc,
				Encounter:    satuSehatEncounterSvc,
				Procedure:    satuSehatProcedureSvc,
				Condition:    satuSehatConditionSvc,
			},
		}

		restSrv := httpServer.NewHTTPServer(&cfg.Server.REST, registry)
		g.Go(func() error {
			logger.Default().Info("SatuSehat REST API running", logger.Int("port", cfg.Server.REST.Port))
			if err := restSrv.Start(&cfg.Server); err != nil && err != http.ErrServerClosed {
				return err
			}
			return nil
		})
	}

	// --- Graceful Shutdown Listener ---
	g.Go(func() error {
		quit := make(chan os.Signal, 1)
		signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
		<-quit
		logger.Default().Warn("Signal received, shutting down SatuSehat service...")
		cancel()
		return nil
	})

	if err := g.Wait(); err != nil {
		logger.Default().Error("SatuSehat service shutdown with error", logger.ErrorField(err))
	} else {
		logger.Default().Info("SatuSehat service shutdown successful")
	}
}
