package router

import (
	"bytes"
	"context"
	"log"
	"net/http"
	"time"

	"bookhoard/internal/database"
	"bookhoard/internal/handlers"
	"bookhoard/internal/services"
	"bookhoard/templates"

	"github.com/golang-jwt/jwt/v5"
	"github.com/jackc/pgx/v5/pgtype"
	"github.com/labstack/echo/v4"

	"github.com/google/uuid"
)

func renderErrorPage(c echo.Context, message string, errorType string) error {
	var buf bytes.Buffer
	err := templates.ErrorPage(message, errorType).Render(c.Request().Context(), &buf)
	if err != nil {
		log.Printf("renderErrorPage failed to render template: %v", err)
		return c.HTML(http.StatusInternalServerError, "Internal server error")
	}
	return c.HTML(http.StatusInternalServerError, buf.String())
}

func registerFrontendRoutes(cfg *Config) {
	e := cfg.Echo

	// ============================================================================
	// FRONTEND ROUTES - DO NOT DELETE
	// These routes serve Server-Side Rendered (SSR) HTML pages for the web UI.
	// They are NOT API endpoints and should NOT be removed during refactors.
	// All authenticated frontend routes use the jwtMiddleware to validate tokens.
	// ============================================================================

	// Use existing JWT middleware (sets database user object in context)
	jwtMiddleware := createJWTMiddleware(cfg)

	// Protected route group for API routes
	protected := e.Group("/api", jwtMiddleware)

	// ============================================================================
	// PUBLIC FRONTEND ROUTES (No authentication required)
	// ============================================================================

	// Public routes for login and registration pages
	e.GET("/login", func(c echo.Context) error {
		var buf bytes.Buffer
		sessionExpired := c.QueryParam("session") == "expired"
		err := templates.Login(sessionExpired).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	})

	e.GET("/register", func(c echo.Context) error {
		var buf bytes.Buffer
		err := templates.Register().Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	})

	// Root route - landing page with smart login detection
	e.GET("/", func(c echo.Context) error {
		var buf bytes.Buffer
		var err error

		tokenString := c.Request().Header.Get("Authorization")
		if tokenString != "" && len(tokenString) > 7 && tokenString[:7] == "Bearer " {
			tokenString = tokenString[7:]
		} else {
			cookie, err := c.Cookie("token")
			if err == nil {
				tokenString = cookie.Value
			}
		}

		loggedIn := false
		if tokenString != "" {
			token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
				return []byte(cfg.Cfg.JWTSecret), nil
			})
			loggedIn = err == nil && token.Valid
		}

		err = templates.Index(loggedIn).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	})

	// ============================================================================
	// PROTECTED FRONTEND ROUTES (Authentication required)
	// ============================================================================

	// Protected frontend routes (no /api prefix)
	frontendProtected := e.Group("", jwtMiddleware, ensureUserExistsMiddleware(cfg))

	// Helper to extract text from pgtype.Text
	getText := func(t pgtype.Text) string {
		if t.Valid {
			return t.String
		}
		return ""
	}

	// Dashboard page
	frontendProtected.GET("/dashboard", func(c echo.Context) error {
		user, err := getTemplateUserWithTheme(c, cfg)
		if err != nil {
			return renderErrorPage(c, "Error loading user", "user_load_error")
		}

		var errorMsg string

		libraryID := c.QueryParam("library_id")
		if libraryID == "" {
			userUUID, _ := uuid.Parse(user.ID)
			libraries, err := cfg.Queries.GetUserVisibleLibraries(c.Request().Context(), uuidToPGType(userUUID))
			if err == nil && len(libraries) > 0 {
				libUUID, _ := uuid.FromBytes(libraries[0].ID.Bytes[0:16])
				libraryID = libUUID.String()
			}
		}

		libUUID, _ := uuid.Parse(libraryID)
		userUUID, _ := uuid.Parse(user.ID)

		prefs, _ := cfg.DashboardService.GetDashboardPreferences(c.Request().Context(), userUUID, libUUID)

		var sections []services.DashboardSection
		sections, err = cfg.DashboardService.GetDashboardSections(
			c.Request().Context(),
			userUUID,
			libUUID,
			int(prefs.ItemsPerSection.Int32),
			prefs.CollectionOrder,
			prefs.HiddenCollections,
		)
		if err != nil {
			log.Printf("Dashboard sections query failed: %v", err)
			sections = []services.DashboardSection{}
			errorMsg = "Error loading dashboard"
		}

		userUUID2, _ := uuid.Parse(user.ID)
		libraries, err := cfg.Queries.GetUserVisibleLibraries(c.Request().Context(), uuidToPGType(userUUID2))
		if err != nil {
			log.Printf("GetUserVisibleLibraries failed: %v", err)
			libraries = []database.GetUserVisibleLibrariesRow{}
			if errorMsg == "" {
				errorMsg = "Error loading libraries"
			}
		}

		libData := make([]templates.LibraryData, len(libraries))
		for i, lib := range libraries {
			libUUID, _ := uuid.FromBytes(lib.ID.Bytes[0:16])
			libData[i] = templates.LibraryData{
				ID:          libUUID.String(),
				Name:        lib.Name,
				Description: getText(lib.Description),
				TypeName:    lib.TypeName,
			}
		}

		sectionData := handlers.BuildSections(sections)

		var buf bytes.Buffer
		err = templates.Dashboard(user, sectionData, libData, libraryID, errorMsg).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	})

	// Collections page
	frontendProtected.GET("/collections", func(c echo.Context) error {
		user, err := getTemplateUserWithTheme(c, cfg)
		if err != nil {
			return renderErrorPage(c, "Error loading user", "user_load_error")
		}

		var errorMsg string
		var collections []database.Collections

		collections, err = cfg.CollectionHandler.GetCollectionsData(c)
		if err != nil {
			log.Printf("GetCollectionsData failed: %v", err)
			collections = []database.Collections{}
			errorMsg = "Error loading collections"
		}

		colData := make([]templates.CollectionData, len(collections))
		for i, col := range collections {
			colData[i] = templates.CollectionData{
				ID:          uuid.UUID(col.ID.Bytes).String(),
				Name:        col.Name,
				Description: getText(col.Description),
				Color:       getText(col.Color),
				Icon:        getText(col.Icon),
			}
		}

		var buf bytes.Buffer
		err = templates.Collection(user, colData, errorMsg).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	})

	// Custom Section Builder page
	frontendProtected.GET("/custom-section", func(c echo.Context) error {
		user, err := getTemplateUserWithTheme(c, cfg)
		if err != nil {
			return renderErrorPage(c, "Error loading user", "user_load_error")
		}

		var errorMsg string
		var libraries []database.GetUserVisibleLibrariesRow

		userUUID, _ := uuid.Parse(user.ID)
		libraries, err = cfg.Queries.GetUserVisibleLibraries(c.Request().Context(), uuidToPGType(userUUID))
		if err != nil {
			log.Printf("GetUserVisibleLibraries failed: %v", err)
			libraries = []database.GetUserVisibleLibrariesRow{}
			errorMsg = "Error loading libraries"
		}

		libData := make([]templates.LibraryData, len(libraries))
		for i, lib := range libraries {
			libUUID, _ := uuid.FromBytes(lib.ID.Bytes[0:16])
			libData[i] = templates.LibraryData{
				ID:          libUUID.String(),
				Name:        lib.Name,
				Description: getText(lib.Description),
				TypeName:    lib.TypeName,
			}
		}

		var buf bytes.Buffer
		err = templates.CustomSectionBuilder(user, libData, errorMsg).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	})

	// Progress page
	frontendProtected.GET("/progress", func(c echo.Context) error {
		user, err := getTemplateUserWithTheme(c, cfg)
		if err != nil {
			return renderErrorPage(c, "Error loading user", "user_load_error")
		}

		var errorMsg string
		var progressData []handlers.ProgressWithMedia

		progressData, err = cfg.ScannerHandler.GetAllProgressData(c)
		if err != nil {
			log.Printf("GetAllProgressData failed: %v", err)
			progressData = []handlers.ProgressWithMedia{}
			errorMsg = "Error loading progress"
		}

		var buf bytes.Buffer
		err = templates.Progress(user, progressData, errorMsg).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	})

	// Devices page
	frontendProtected.GET("/devices", func(c echo.Context) error {
		user, err := getTemplateUserWithTheme(c, cfg)
		if err != nil {
			return renderErrorPage(c, "Error loading user", "user_load_error")
		}

		var errorMsg string
		var devices []handlers.DeviceInfo
		var pendingList []templates.PendingRegistrationData

		devices, err = cfg.DeviceHandler.GetDevicesData(c)
		if err != nil {
			log.Printf("GetDevicesData failed: %v", err)
			devices = []handlers.DeviceInfo{}
			errorMsg = "Error loading devices"
		}

		pendingMaps, err := cfg.DeviceHandler.GetPendingRegistrationsData(c)
		if err != nil {
			log.Printf("GetPendingRegistrationsData failed: %v", err)
			pendingList = []templates.PendingRegistrationData{}
			if errorMsg == "" {
				errorMsg = "Error loading pending registrations"
			}
		} else {
			pendingList = convertPending(pendingMaps)
		}

		var buf bytes.Buffer
		err = templates.Devices(user, devices, pendingList, errorMsg, cfg.Cfg.BaseURL).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	})

	// Conflicts page
	frontendProtected.GET("/conflicts", func(c echo.Context) error {
		user, err := getTemplateUserWithTheme(c, cfg)
		if err != nil {
			return renderErrorPage(c, "Error loading user", "user_load_error")
		}

		var errorMsg string
		var conflictsData []handlers.ConflictDetailResponse
		var total, unresolved int

		conflictsData, total, unresolved, err = cfg.ConflictHandler.GetConflictsData(c)
		if err != nil {
			log.Printf("GetConflictsData failed: %v", err)
			conflictsData = []handlers.ConflictDetailResponse{}
			total = 0
			unresolved = 0
			errorMsg = "Error loading conflicts"
		}

		var buf bytes.Buffer
		err = templates.Conflicts(user, conflictsData, total, unresolved, errorMsg).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	})

	// Analytics page
	frontendProtected.GET("/analytics", func(c echo.Context) error {
		user, err := getTemplateUserWithTheme(c, cfg)
		if err != nil {
			return renderErrorPage(c, "Error loading user", "user_load_error")
		}
		var buf bytes.Buffer
		err = templates.Analytics(user).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	})

	// ============================================================================
	// ADMIN FRONTEND ROUTES
	// ============================================================================

	// Admin routes
	frontendProtected.GET("/admin", handlers.AdminMiddleware(func(c echo.Context) error {
		user, err := getTemplateUserWithTheme(c, cfg)
		if err != nil {
			return renderErrorPage(c, "Error loading user", "user_load_error")
		}
		var buf bytes.Buffer
		err = templates.Admin(user).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	}))

	frontendProtected.GET("/admin/", handlers.AdminMiddleware(func(c echo.Context) error {
		user, err := getTemplateUserWithTheme(c, cfg)
		if err != nil {
			return renderErrorPage(c, "Error loading user", "user_load_error")
		}
		var buf bytes.Buffer
		err = templates.Admin(user).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	}))

	frontendProtected.GET("/admin/profile", handlers.AdminMiddleware(func(c echo.Context) error {
		user, err := getTemplateUserWithTheme(c, cfg)
		if err != nil {
			return renderErrorPage(c, "Error loading user", "user_load_error")
		}
		var buf bytes.Buffer
		err = templates.AdminProfile(user).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	}))

	frontendProtected.GET("/admin/library", handlers.AdminMiddleware(func(c echo.Context) error {
		user, err := getTemplateUserWithTheme(c, cfg)
		if err != nil {
			return renderErrorPage(c, "Error loading user", "user_load_error")
		}
		var buf bytes.Buffer
		err = templates.AdminLibrary(user).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	}))

	// ============================================================================
	// LEGACY API ROUTES (for backward compatibility)
	// ============================================================================

	// Keep legacy routes under /api for existing API consumers
	protected.GET("/devices-page", func(c echo.Context) error {
		user, err := getTemplateUserWithTheme(c, cfg)
		if err != nil {
			return renderErrorPage(c, "Error loading user", "user_load_error")
		}
		var errorMsg string
		var devices []handlers.DeviceInfo
		var pendingList []templates.PendingRegistrationData

		devices, err = cfg.DeviceHandler.GetDevicesData(c)
		if err != nil {
			log.Printf("GetDevicesData failed: %v", err)
			devices = []handlers.DeviceInfo{}
			errorMsg = "Error loading devices"
		}

		pendingMaps, err := cfg.DeviceHandler.GetPendingRegistrationsData(c)
		if err != nil {
			log.Printf("GetPendingRegistrationsData failed: %v", err)
			pendingList = []templates.PendingRegistrationData{}
			if errorMsg == "" {
				errorMsg = "Error loading pending registrations"
			}
		} else {
			pendingList = convertPending(pendingMaps)
		}

		var buf bytes.Buffer
		err = templates.Devices(user, devices, pendingList, errorMsg, cfg.Cfg.BaseURL).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	})

	protected.GET("/conflicts-page", func(c echo.Context) error {
		user, err := getTemplateUserWithTheme(c, cfg)
		if err != nil {
			return renderErrorPage(c, "Error loading user", "user_load_error")
		}

		var errorMsg string
		var conflictsData []handlers.ConflictDetailResponse
		var total, unresolved int

		conflictsData, total, unresolved, err = cfg.ConflictHandler.GetConflictsData(c)
		if err != nil {
			log.Printf("GetConflictsData failed: %v", err)
			conflictsData = []handlers.ConflictDetailResponse{}
			total = 0
			unresolved = 0
			errorMsg = "Error loading conflicts"
		}

		var buf bytes.Buffer
		err = templates.Conflicts(user, conflictsData, total, unresolved, errorMsg).Render(c.Request().Context(), &buf)
		if err != nil {
			return err
		}
		return c.HTML(http.StatusOK, buf.String())
	})

	// ============================================================================
	// HEALTH CHECK
	// ============================================================================

	// Health check
	e.GET("/health", func(c echo.Context) error {
		ctx, cancel := context.WithTimeout(c.Request().Context(), 2*time.Second)
		defer cancel()

		if err := pingDB(cfg, ctx); err != nil {
			return c.JSON(http.StatusServiceUnavailable, map[string]string{
				"status": "unhealthy",
				"error":  "database unavailable",
			})
		}
		return c.JSON(http.StatusOK, map[string]string{
			"status":   "healthy",
			"database": "connected",
		})
	})
}
