package api

import (
	"time"

	"github.com/calendarapi/internal/api/handlers"
	"github.com/calendarapi/internal/api/openapi"
	"github.com/calendarapi/internal/config"
	mw "github.com/calendarapi/internal/middleware"
	"github.com/go-chi/chi/v5"
	chimw "github.com/go-chi/chi/v5/middleware"
	"github.com/go-chi/cors"
)

type Handlers struct {
	Auth         *handlers.AuthHandler
	User         *handlers.UserHandler
	Calendar     *handlers.CalendarHandler
	Sharing      *handlers.SharingHandler
	Event        *handlers.EventHandler
	Reminder     *handlers.ReminderHandler
	Attendee     *handlers.AttendeeHandler
	Contact      *handlers.ContactHandler
	Availability *handlers.AvailabilityHandler
	Booking      *handlers.BookingHandler
	APIKey       *handlers.APIKeyHandler
	ICS          *handlers.ICSHandler
}

func NewRouter(h Handlers, authMW *mw.AuthMiddleware, rateLimiter *mw.RateLimiter, cfg *config.Config) *chi.Mux {
	r := chi.NewRouter()

	r.Use(chimw.RequestID)
	r.Use(chimw.Logger)
	r.Use(chimw.Recoverer)
	r.Use(chimw.RealIP)
	r.Use(chimw.Timeout(30 * time.Second))
	origins := cfg.CORSOrigins
	if len(origins) == 0 {
		origins = []string{"http://localhost:5173", "http://127.0.0.1:5173"}
	}
	r.Use(cors.Handler(cors.Options{
		AllowedOrigins:   origins,
		AllowedMethods:   []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
		AllowedHeaders:   []string{"Accept", "Authorization", "Content-Type", "X-API-Key"},
		ExposedHeaders:   []string{"Link"},
		AllowCredentials: true,
		MaxAge:           300,
	}))
	r.Use(rateLimiter.Limit)

	// OpenAPI spec and Swagger UI
	r.Get("/openapi.json", openapi.SpecHandler)
	r.Get("/docs", openapi.DocsHandler)

	// Public routes (no auth)
	r.Group(func(r chi.Router) {
		r.Post("/auth/register", h.Auth.Register)
		r.Post("/auth/login", h.Auth.Login)
		r.Post("/auth/refresh", h.Auth.Refresh)

		r.Get("/booking/{token}/availability", h.Booking.GetAvailability)
		r.Post("/booking/{token}/reserve", h.Booking.Reserve)

		r.Get("/cal/{token}/feed.ics", h.ICS.PublicFeed)

		// Public availability (no auth) - for external booking tools
		r.Get("/availability/aggregate", h.Availability.GetAggregate)
		r.Get("/availability/{token}", h.Availability.GetByToken)
	})

	// Authenticated routes
	r.Group(func(r chi.Router) {
		r.Use(authMW.Authenticate)

		// Auth
		r.Post("/auth/logout", h.Auth.Logout)
		r.Get("/auth/me", h.Auth.Me)

		// Users
		r.Get("/users/me", h.User.GetMe)
		r.Put("/users/me", h.User.UpdateMe)
		r.Delete("/users/me", h.User.DeleteMe)

		// API Keys
		r.Post("/api-keys", h.APIKey.Create)
		r.Get("/api-keys", h.APIKey.List)
		r.Delete("/api-keys/{id}", h.APIKey.Revoke)

		// Calendars
		r.Route("/calendars", func(r chi.Router) {
			r.With(mw.RequireScope("calendars", "read")).Get("/", h.Calendar.List)
			r.With(mw.RequireScope("calendars", "write")).Post("/", h.Calendar.Create)
			r.With(mw.RequireScope("calendars", "write")).Post("/import", h.ICS.Import)
			r.With(mw.RequireScope("calendars", "write")).Post("/import-url", h.ICS.ImportURL)
			r.With(mw.RequireScope("calendars", "write")).Post("/add-from-url", h.ICS.AddFromURL)

			r.Route("/{id}", func(r chi.Router) {
				r.With(mw.RequireScope("calendars", "read")).Get("/", h.Calendar.Get)
				r.With(mw.RequireScope("calendars", "write")).Put("/", h.Calendar.Update)
				r.With(mw.RequireScope("calendars", "write")).Delete("/", h.Calendar.Delete)

				// Sharing
				r.With(mw.RequireScope("calendars", "write")).Post("/share", h.Sharing.Share)
				r.With(mw.RequireScope("calendars", "read")).Get("/members", h.Sharing.ListMembers)
				r.With(mw.RequireScope("calendars", "write")).Delete("/members/{userID}", h.Sharing.RemoveMember)

				// Booking link
				r.With(mw.RequireScope("booking", "write")).Post("/booking-link", h.Booking.CreateLink)

				// ICS
				r.With(mw.RequireScope("calendars", "read")).Get("/export.ics", h.ICS.Export)

				// Subscriptions
				r.With(mw.RequireScope("calendars", "read")).Get("/subscriptions", h.ICS.ListSubscriptions)
				r.With(mw.RequireScope("calendars", "write")).Post("/subscriptions", h.ICS.AddSubscription)
				r.With(mw.RequireScope("calendars", "write")).Delete("/subscriptions/{subId}", h.ICS.DeleteSubscription)
				r.With(mw.RequireScope("calendars", "write")).Post("/subscriptions/{subId}/sync", h.ICS.SyncSubscription)
			})
		})

		// Events
		r.Route("/events", func(r chi.Router) {
			r.With(mw.RequireScope("events", "read")).Get("/", h.Event.List)
			r.With(mw.RequireScope("events", "write")).Post("/", h.Event.Create)

			r.Route("/{id}", func(r chi.Router) {
				r.With(mw.RequireScope("events", "read")).Get("/", h.Event.Get)
				r.With(mw.RequireScope("events", "write")).Put("/", h.Event.Update)
				r.With(mw.RequireScope("events", "write")).Delete("/", h.Event.Delete)

				// Reminders
				r.With(mw.RequireScope("events", "write")).Post("/reminders", h.Reminder.Add)
				r.With(mw.RequireScope("events", "write")).Delete("/reminders/{reminderID}", h.Reminder.Delete)

				// Attendees
				r.With(mw.RequireScope("events", "write")).Post("/attendees", h.Attendee.Add)
				r.With(mw.RequireScope("events", "write")).Put("/attendees/{attendeeID}", h.Attendee.UpdateStatus)
				r.With(mw.RequireScope("events", "write")).Delete("/attendees/{attendeeID}", h.Attendee.Delete)
			})
		})

		// Contacts
		r.Route("/contacts", func(r chi.Router) {
			r.With(mw.RequireScope("contacts", "read")).Get("/", h.Contact.List)
			r.With(mw.RequireScope("contacts", "write")).Post("/", h.Contact.Create)

			r.Route("/{id}", func(r chi.Router) {
				r.With(mw.RequireScope("contacts", "read")).Get("/", h.Contact.Get)
				r.With(mw.RequireScope("contacts", "write")).Put("/", h.Contact.Update)
				r.With(mw.RequireScope("contacts", "write")).Delete("/", h.Contact.Delete)
			})
		})

		// Availability
		r.With(mw.RequireScope("availability", "read")).Get("/availability", h.Availability.Get)
	})

	return r
}
