package api

import (
	"net/http"
	"time"

	"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/config"
	"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/handlers"
	apiMiddleware "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/middleware"
	"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/service"
	"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/auth"
	"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/proxy"

	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
	"github.com/go-chi/cors"
	"go.uber.org/zap"
)

// SetupRouter configures and returns the API router
func SetupRouter(cfg *config.Config, logger *zap.Logger) http.Handler {
	r := chi.NewRouter()

	// Base middleware
	r.Use(middleware.RequestID)
	r.Use(middleware.RealIP)
	r.Use(middleware.Recoverer)
	r.Use(apiMiddleware.Logger(logger))

	// CORS configuration
	r.Use(cors.Handler(cors.Options{
		AllowedOrigins:   []string{"*"}, // In production, restrict this to your frontend domains
		AllowedMethods:   []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
		AllowedHeaders:   []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
		ExposedHeaders:   []string{"Link"},
		AllowCredentials: true,
		MaxAge:           300, // Maximum value not ignored by any of major browsers
	}))

	// Initialize Google auth client for proxy
	googleAuth, err := auth.NewGoogleClient(cfg.Google.CredentialsPath)
	if err != nil {
		logger.Fatal("Failed to initialize Google auth client", zap.Error(err))
	}

	// Initialize Healthcare API client
	healthcareClient := proxy.NewClient(googleAuth, cfg.Google)

	// Initialize JWT auth service
	jwtSecret := cfg.Auth.JWTSecret
	if jwtSecret == "" {
		jwtSecret = "vQ6PQqUyh7pBNOytClgN+Nw1XBq7F8Qo6VP3VwIqvHY=" // Default from your example, should be set in config
	}

	// Convert config values to time.Duration
	accessExpiry := time.Duration(cfg.Auth.AccessTokenExpiry) * time.Minute
	refreshExpiry := time.Duration(cfg.Auth.RefreshTokenExpiry) * time.Hour

	// Create JWT manager with config values
	jwtManager := auth.NewJWTManager(jwtSecret, accessExpiry, refreshExpiry)
	authService := service.NewAuthService(jwtManager)

	// Public routes that don't require authentication
	r.Group(func(r chi.Router) {
		// Health check
		r.Get("/health", handlers.HealthCheck)

		// Authentication endpoints
		r.Route("/auth", func(r chi.Router) {
			authHandler := handlers.NewAuthHandler(logger, authService)
			r.Post("/login", authHandler.Login)
			r.Post("/refresh", authHandler.RefreshToken)
			r.Post("/logout", authHandler.Logout)
		})
	})

	// Protected routes that require authentication
	r.Group(func(r chi.Router) {
		// Apply authentication middleware
		r.Use(apiMiddleware.Auth(authService, logger))

		// DICOM Web routes
		r.Route("/dicomWeb", func(r chi.Router) {
			// Add audit logging middleware to DICOM routes
			r.Use(apiMiddleware.AuditLog(logger))

			// Add patient view restriction for patient role
			r.Use(apiMiddleware.PatientViewRestriction(logger))

			// Create handler for all DICOM requests
			dicomHandler := handlers.NewDicomHandler(healthcareClient, logger)

			// Common routes for studies with role-specific handling
			r.Route("/studies", func(r chi.Router) {
				// StudyInstanceUID parameter routes - accessible by all roles
				r.Get("/{studyInstanceUID}", dicomHandler.ForwardRequest)        // Study details
				r.Get("/{studyInstanceUID}/series", dicomHandler.ForwardRequest) // Series list for study

				// Deep hierarchy routes - accessible by patients and all doctors
				r.Get("/{studyInstanceUID}/series/{seriesUID}/metadata", dicomHandler.ForwardRequest)
				r.Get("/{studyInstanceUID}/series/{seriesUID}/instances/{instanceUID}/frames/{frame}", dicomHandler.ForwardRequest)

				// Query routes - accessible by all roles
				r.Get("/", dicomHandler.ForwardRequest) // Study list with filters
			})

			// Expertise doctors have full access to all DICOM endpoints
			r.With(apiMiddleware.RoleRequired("expertise_doctor")).HandleFunc("/*", dicomHandler.ForwardRequest)
		})
	})

	return r
}
