package httpapi

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"

	"productier/apps/backend/internal/store"
)

// OAuth state for CSRF protection
type oauthState struct {
	State        string `json:"state"`
	Provider     string `json:"provider"`
	WorkspaceSlug string `json:"workspaceSlug"`
	RedirectURL  string `json:"redirectUrl"`
}

// In-memory state store (in production, use Redis or database)
var oauthStates = make(map[string]oauthState)

func (s *Server) registerOAuthRoutes(group *gin.RouterGroup) {
	// Google Calendar OAuth
	group.GET("/oauth/google-calendar/connect", func(c *gin.Context) {
		workspaceSlug := c.Query("workspaceSlug")
		if _, ok := s.requireWorkspaceMember(c, workspaceSlug); !ok {
			return
		}

		state := uuid.NewString()
		redirectURL := c.Query("redirect")
		if redirectURL == "" {
			redirectURL = fmt.Sprintf("/app/%s/integrations", workspaceSlug)
		}

		oauthStates[state] = oauthState{
			State:        state,
			Provider:     "google_calendar",
			WorkspaceSlug: workspaceSlug,
			RedirectURL:  redirectURL,
		}

		// Build Google OAuth URL
		// In production, use actual OAuth credentials from config
		authURL := fmt.Sprintf(
			"https://accounts.google.com/o/oauth2/v2/auth?client_id=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&access_type=offline&prompt=consent",
			url.QueryEscape(s.config.GoogleClientID),
			url.QueryEscape(s.config.GoogleRedirectURI),
			url.QueryEscape("https://www.googleapis.com/auth/calendar.events https://www.googleapis.com/auth/calendar.readonly"),
			state,
		)

		c.JSON(http.StatusOK, gin.H{"authUrl": authURL})
	})

	group.GET("/oauth/google-calendar/callback", func(c *gin.Context) {
		code := c.Query("code")
		state := c.Query("state")

		oauthState, exists := oauthStates[state]
		if !exists || oauthState.Provider != "google_calendar" {
			s.writeStatusError(c, http.StatusBadRequest, "invalid oauth state")
			return
		}
		delete(oauthStates, state)

		// Exchange code for tokens
		// In production, make actual HTTP request to Google's token endpoint
		// For now, we'll create a placeholder integration
		integration := s.store.CreateIntegration(store.CreateIntegrationInput{
			WorkspaceSlug: oauthState.WorkspaceSlug,
			Provider:      "google_calendar",
			Name:          "Google Calendar",
			Config:        `{"calendar_id": "primary"}`,
			Credentials:   code, // In production, store actual tokens
		})

		// Redirect back to the app
		c.Redirect(http.StatusTemporaryRedirect, oauthState.RedirectURL+"?connected=google_calendar")
	})

	// Slack OAuth
	group.GET("/oauth/slack/connect", func(c *gin.Context) {
		workspaceSlug := c.Query("workspaceSlug")
		if _, ok := s.requireWorkspaceMember(c, workspaceSlug); !ok {
			return
		}

		state := uuid.NewString()
		redirectURL := c.Query("redirect")
		if redirectURL == "" {
			redirectURL = fmt.Sprintf("/app/%s/integrations", workspaceSlug)
		}

		oauthStates[state] = oauthState{
			State:        state,
			Provider:     "slack",
			WorkspaceSlug: workspaceSlug,
			RedirectURL:  redirectURL,
		}

		// Build Slack OAuth URL
		scopes := "chat:write,channels:read,groups:read,im:read"
		authURL := fmt.Sprintf(
			"https://slack.com/oauth/v2/authorize?client_id=%s&scope=%s&redirect_uri=%s&state=%s",
			url.QueryEscape(s.config.SlackClientID),
			url.QueryEscape(scopes),
			url.QueryEscape(s.config.SlackRedirectURI),
			state,
		)

		c.JSON(http.StatusOK, gin.H{"authUrl": authURL})
	})

	group.GET("/oauth/slack/callback", func(c *gin.Context) {
		code := c.Query("code")
		state := c.Query("state")

		oauthState, exists := oauthStates[state]
		if !exists || oauthState.Provider != "slack" {
			s.writeStatusError(c, http.StatusBadRequest, "invalid oauth state")
			return
		}
		delete(oauthStates, state)

		// Exchange code for tokens
		// In production, make actual HTTP request to Slack's token endpoint
		// For now, we'll create a placeholder integration
		integration := s.store.CreateIntegration(store.CreateIntegrationInput{
			WorkspaceSlug: oauthState.WorkspaceSlug,
			Provider:      "slack",
			Name:          "Slack",
			Config:        `{"channel": "general"}`,
			Credentials:   code, // In production, store actual tokens
		})

		// Redirect back to the app
		c.Redirect(http.StatusTemporaryRedirect, oauthState.RedirectURL+"?connected=slack&integration_id="+integration.ID)
	})

	// Disconnect integration
	group.POST("/integrations/:integrationId/disconnect", func(c *gin.Context) {
		integration, err := s.store.GetIntegrationByID(c.Param("integrationId"))
		if err != nil {
			s.writeStatusError(c, http.StatusNotFound, err.Error())
			return
		}
		if _, ok := s.requireWorkspaceMember(c, integration.WorkspaceSlug); !ok {
			return
		}

		// In production, revoke OAuth tokens with the provider
		// For Google: https://oauth2.googleapis.com/revoke?token=...
		// For Slack: https://slack.com/api/auth.revoke?token=...

		if err := s.store.DeleteIntegration(integration.ID); err != nil {
			s.writeStatusError(c, http.StatusInternalServerError, err.Error())
			return
		}
		c.JSON(http.StatusOK, gin.H{"ok": true})
	})
}

// SyncGoogleCalendar syncs events with Google Calendar
func (s *Server) SyncGoogleCalendar(workspaceSlug string) error {
	integrations := s.store.ListIntegrations(workspaceSlug)
	for _, integration := range integrations {
		if integration.Provider == "google_calendar" && integration.Status == "active" {
			// In production, use the stored credentials to:
			// 1. Fetch events from Google Calendar
			// 2. Create/update events in our database
			// 3. Push local events to Google Calendar
			// This would be done via the Google Calendar API client
		}
	}
	return nil
}

// SendSlackNotification sends a notification to Slack
func (s *Server) SendSlackNotification(workspaceSlug, channel, message string) error {
	integrations := s.store.ListIntegrations(workspaceSlug)
	for _, integration := range integrations {
		if integration.Provider == "slack" && integration.Status == "active" {
			// Parse config to get channel
			var config struct {
				Channel string `json:"channel"`
			}
			if err := json.Unmarshal([]byte(integration.Config), &config); err != nil {
				continue
			}

			// In production, use the stored credentials to:
			// 1. Post message to Slack channel via webhook or API
			// This would be done via the Slack API client
		}
	}
	return nil
}

// Helper to parse JSON config
func parseConfig(configStr string) map[string]interface{} {
	var config map[string]interface{}
	if err := json.NewDecoder(strings.NewReader(configStr)).Decode(&config); err != nil {
		return make(map[string]interface{})
	}
	return config
}