package app

import (
	"context"
	"net/http"

	"github.com/jackc/pgx/v5/pgxpool"

	"nexavpn/backend/internal/audit"
	"nexavpn/backend/internal/auth"
	"nexavpn/backend/internal/config"
	"nexavpn/backend/internal/db"
	"nexavpn/backend/internal/device"
	"nexavpn/backend/internal/gateway"
	"nexavpn/backend/internal/group"
	"nexavpn/backend/internal/httpserver"
	"nexavpn/backend/internal/ipam"
	"nexavpn/backend/internal/policy"
	"nexavpn/backend/internal/user"
)

type App struct {
	DB     *pgxpool.Pool
	Router http.Handler
}

func New(cfg config.Config) (*App, error) {
	ctx := context.Background()

	pool, err := db.Connect(ctx, cfg.DatabaseURL)
	if err != nil {
		return nil, err
	}

	authRepo := auth.NewPGRepository(pool)
	authService := auth.NewService(authRepo, cfg.JWTSecret, cfg.JWTIssuer, cfg.AccessTokenTTL, cfg.RefreshTokenTTL)

	userService := user.NewService(user.NewPGRepository(pool))
	groupService := group.NewService(group.NewPGRepository(pool))
	policyService := policy.NewService(policy.NewPGRepository(pool))
	gatewayService := gateway.NewService(gateway.NewPGRepository(pool))
	deviceService := device.NewService(device.NewPGRepository(pool), policyService, gatewayService, ipam.NewService())
	auditService := audit.NewService(audit.NewPGRepository(pool))

	router := httpserver.NewRouter(cfg.JWTSecret, httpserver.Handlers{
		Auth:    auth.NewHandler(authService, auditService),
		User:    user.NewHandler(userService, auditService),
		Device:  device.NewHandler(deviceService, auditService),
		Group:   group.NewHandler(groupService, auditService),
		Policy:  policy.NewHandler(policyService, auditService),
		Gateway: gateway.NewHandler(gatewayService, cfg.GatewayBootstrapToken),
		Audit:   audit.NewHandler(auditService),
	})

	return &App{
		DB:     pool,
		Router: router,
	}, nil
}

func (a *App) Close() {
	if a.DB != nil {
		a.DB.Close()
	}
}
