package api

import (
	"context"
	"io/fs"
	"net/http"
	"os"

	"github.com/go-chi/chi/v5"
	"github.com/mark3labs/mcp-go/server"
	"github.com/mish/dealspace/lib"
)

// NewRouter creates the main router with all routes registered.
func NewRouter(db *lib.DB, cfg *lib.Config, store lib.ObjectStore, websiteFS fs.FS, portalFS fs.FS, mcpServer *server.MCPServer) *chi.Mux {
	r := chi.NewRouter()
	h := NewHandlers(db, cfg, store)
	oauth := NewOAuthHandlers(db, cfg)

	// Global middleware
	r.Use(LoggingMiddleware)
	r.Use(CORSMiddleware)
	r.Use(SecurityHeadersMiddleware)
	r.Use(BlockDatabaseMiddleware) // HARD RULE: no raw DB files served under any circumstance
	r.Use(RateLimitMiddleware(120)) // 120 req/min per IP

	// Health check (unauthenticated)
	r.Get("/health", h.Health)

	// Chat endpoint (unauthenticated, for Aria chatbot)
	r.Post("/api/chat", h.ChatHandler)
	r.Options("/api/chat", h.ChatHandler)

	// Auth endpoints (unauthenticated — email challenge OTP flow)
	r.Post("/api/auth/challenge", h.Challenge)
	r.Post("/api/auth/verify", h.Verify)

	// Auth endpoints (need token for logout/me)
	r.Group(func(r chi.Router) {
		r.Use(AuthMiddleware(db, cfg.JWTSecret))
		r.Post("/api/auth/logout", h.Logout)
		r.Get("/api/auth/me", h.Me)
	})

	// API routes (authenticated)
	r.Route("/api", func(r chi.Router) {
		r.Use(AuthMiddleware(db, cfg.JWTSecret))

		// Tasks (cross-project)
		r.Get("/tasks", h.GetAllTasks)

		// Projects
		r.Get("/projects", h.GetAllProjects)
		r.Post("/projects", h.CreateProject)
		r.Get("/projects/{projectID}", h.GetProjectDetail)
		r.Get("/projects/{projectID}/detail", h.GetProjectDetail) // legacy alias
		r.Delete("/projects/{projectID}", h.DeleteProject)

		// Workstreams
		r.Post("/projects/{projectID}/workstreams", h.CreateWorkstream)

		// Entries
		r.Get("/projects/{projectID}/entries", h.ListEntries)
		r.Post("/projects/{projectID}/entries", h.CreateEntry)
		r.Put("/projects/{projectID}/entries/{entryID}", h.UpdateEntry)
		r.Delete("/projects/{projectID}/entries/{entryID}", h.DeleteEntry)

		// Task inbox (per-project)
		r.Get("/projects/{projectID}/tasks", h.GetMyTasks)

		// Requests (list, tree, and import)
		r.Get("/projects/{projectID}/requests", h.ListRequests)
		r.Get("/projects/{projectID}/requests/tree", h.ListRequestTree)
		r.Post("/projects/{projectID}/requests", h.CreateRequestList)
		r.Post("/projects/{projectID}/requests/new", h.CreateRequest)
		r.Post("/projects/{projectID}/sections", h.CreateSection)
		r.Post("/projects/{projectID}/requests/import", h.ImportRequests)
		r.Post("/projects/{projectID}/requests/import-template", h.ImportTemplate)
		r.Get("/templates", h.ListTemplates)
		r.Post("/templates", h.SaveTemplate)

		// Request detail
		r.Get("/requests/{requestID}", h.GetRequestDetail)

		// Entry move (drag & drop)
		r.Post("/projects/{projectID}/entries/{entryID}/move", h.MoveEntry)

		// Answer links
		r.Get("/projects/{projectID}/requests/{requestID}/links", h.ListAnswerLinks)
		r.Post("/projects/{projectID}/requests/{requestID}/links", h.CreateAnswerLink)
		r.Delete("/projects/{projectID}/requests/{requestID}/links/{answerID}", h.DeleteAnswerLink)

		// Answers (picker)
		r.Get("/projects/{projectID}/answers", h.ListAnswers)

		// File upload/download/preview
		r.Post("/projects/{projectID}/objects", h.UploadObject)
		r.Get("/projects/{projectID}/objects/{objectID}", h.DownloadObject)
		r.Get("/projects/{projectID}/objects/{objectID}/preview", h.PreviewObject)

		// Request list visibility
		r.Patch("/projects/{projectID}/entries/{entryID}/visibility", h.UpdateRequestListVisibility)

		// Super admin endpoints
		// Organizations (platform level)
		r.Get("/orgs", h.ListOrgs)
		r.Post("/orgs", h.CreateOrg)
		r.Put("/orgs/{orgID}", h.UpdateOrg)
		r.Put("/admin/test-role", h.SetTestRole)
		r.Get("/orgs/{orgID}", h.GetOrg)
		r.Patch("/orgs/{orgID}", h.UpdateOrg)

		// Deal orgs (per project)
		r.Get("/projects/{projectID}/orgs", h.ListDealOrgs)
		r.Post("/projects/{projectID}/orgs", h.CreateDealOrg)
		r.Delete("/projects/{projectID}/orgs/{dealOrgID}", h.DeleteDealOrg)
		r.Post("/projects/{projectID}/orgs/add", h.AddOrgToDeal)

		// Scrape (LLM-powered org lookup)
		r.Post("/scrape/org", h.ScrapeOrg)

		r.Get("/admin/users", h.AdminListUsers)
		r.Get("/admin/projects", h.AdminListProjects)
		r.Get("/admin/audit", h.AdminAuditLog)
		r.Post("/admin/impersonate", h.AdminImpersonate)
	})

	// OAuth metadata (unauthenticated, auto-discovery)
	r.Get("/.well-known/oauth-authorization-server", oauth.Metadata)
	r.Get("/.well-known/oauth-protected-resource", oauth.ResourceMetadata)

	// OAuth endpoints
	r.Get("/oauth/authorize", oauth.Authorize)
	r.Post("/oauth/authorize", oauth.AuthorizeApprove)
	r.Post("/oauth/token", oauth.Token)
	r.Post("/oauth/revoke", oauth.Revoke)

	// MCP endpoint (OAuth bearer auth)
	if mcpServer != nil {
		mcpHTTP := server.NewStreamableHTTPServer(mcpServer,
			server.WithEndpointPath("/mcp"),
			server.WithHTTPContextFunc(func(ctx context.Context, r *http.Request) context.Context {
				if uid := UserIDFromContext(r.Context()); uid != "" {
					return context.WithValue(ctx, ctxUserID, uid)
				}
				return ctx
			}),
		)
		r.Group(func(r chi.Router) {
			r.Use(OAuthBearerAuth(db))
			r.Handle("/mcp", mcpHTTP)
		})
	}

	// Request list templates (JSON)
	r.Handle("/templates/*", http.StripPrefix("/templates/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		dirs := []string{"templates", "/opt/dealspace/templates"}
		for _, dir := range dirs {
			fp := dir + "/" + r.URL.Path
			if _, err := os.Stat(fp); err == nil {
				w.Header().Set("Content-Type", "application/json")
				http.ServeFile(w, r, fp)
				return
			}
		}
		http.NotFound(w, r)
	})))

	// Static files (portal + website CSS/JS)
	r.Handle("/static/*", http.StripPrefix("/static/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		dirs := []string{
			"portal/static", "/opt/dealspace/portal/static",
			"website/static", "/opt/dealspace/website/static",
		}
		for _, dir := range dirs {
			fp := dir + "/" + r.URL.Path
			if _, err := os.Stat(fp); err == nil {
				http.FileServer(http.Dir(dir)).ServeHTTP(w, r)
				return
			}
		}
		http.NotFound(w, r)
	})))

	// Portal app routes (serve templates, auth checked client-side via JS)
	r.Get("/app", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/app/projects", http.StatusFound)
	})
	r.Get("/app/login", h.ServeLogin)
	r.Get("/app/tasks", h.ServeAppTasks)
	r.Get("/app/projects", h.ServeAppProjects)
	r.Get("/app/projects/{id}", h.ServeAppProject)
	r.Get("/app/requests/{id}", h.ServeAppRequest)
	r.Get("/app/orgs", h.ServeAppOrgs)

	// Admin UI (super admin only, auth checked client-side)
	r.Get("/admin", h.ServeAdmin)
	r.Get("/admin/*", h.ServeAdmin)

	// Marketing website pages (template-based)
	r.Get("/", h.ServeWebsiteIndex)
	r.Get("/features", h.ServeWebsiteFeatures)
	r.Get("/pricing", h.ServeWebsitePricing)
	r.Get("/security", h.ServeWebsiteSecurity)
	r.Get("/privacy", h.ServeWebsitePrivacy)
	r.Get("/terms", h.ServeWebsiteTerms)
	r.Get("/dpa", h.ServeWebsiteDPA)
	r.Get("/soc2", h.ServeWebsiteSOC2)

	// Website static assets (embedded files) — serves at root, must be last
	if websiteFS != nil {
		websiteHandler := http.FileServerFS(websiteFS)
		r.Handle("/*", websiteHandler)
	}

	return r
}
