package server

import (
	"net/http"
	"time"

	"gophergate/internal/db"

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

func (s *Server) handleGetClients(c *gin.Context) {
	var clients []db.Client
	err := s.database.Select(&clients, "SELECT * FROM clients ORDER BY created_at DESC")
	if err != nil {
		c.JSON(http.StatusInternalServerError, ErrorResponse(err.Error()))
		return
	}

	type UIClient struct {
		ID                 string     `json:"id"`
		Name               string     `json:"name"`
		Description        string     `json:"description"`
		CreatedAt          time.Time  `json:"created_at"`
		LastUsed           *time.Time `json:"last_used"`
		RequestsCount      int        `json:"requests_count"`
		TokensCount        int        `json:"tokens_count"`
		Status             string     `json:"status"`
		RateLimitPerMinute int        `json:"rate_limit_per_minute"`
	}

	uiClients := make([]UIClient, len(clients))
	for i, cl := range clients {
		status := "active"
		if !cl.IsActive {
			status = "disabled"
		}

		name := ""
		if cl.Name != nil {
			name = *cl.Name
		}
		desc := ""
		if cl.Description != nil {
			desc = *cl.Description
		}

		var lastUsedStr string
		_ = s.database.Get(&lastUsedStr, "SELECT MAX(last_used_at) FROM client_tokens WHERE client_id = ?", cl.ClientID)

		var lastUsed *time.Time
		if lastUsedStr != "" {
			if t, err := time.Parse("2006-01-02 15:04:05", lastUsedStr); err == nil {
				lastUsed = &t
			}
		}

		uiClients[i] = UIClient{
			ID:                 cl.ClientID,
			Name:               name,
			Description:        desc,
			CreatedAt:          cl.CreatedAt,
			LastUsed:           lastUsed,
			RequestsCount:      cl.TotalRequests,
			TokensCount:        cl.TotalTokens,
			Status:             status,
			RateLimitPerMinute: cl.RateLimitPerMinute,
		}
	}

	c.JSON(http.StatusOK, SuccessResponse(uiClients))
}

func (s *Server) handleGetClient(c *gin.Context) {
	id := c.Param("id")
	var cl db.Client
	err := s.database.Get(&cl, "SELECT * FROM clients WHERE client_id = ?", id)
	if err != nil {
		c.JSON(http.StatusNotFound, ErrorResponse("Client not found"))
		return
	}

	name := ""
	if cl.Name != nil {
		name = *cl.Name
	}
	desc := ""
	if cl.Description != nil {
		desc = *cl.Description
	}

	c.JSON(http.StatusOK, SuccessResponse(gin.H{
		"id":                    cl.ClientID,
		"name":                  name,
		"description":           desc,
		"is_active":             cl.IsActive,
		"rate_limit_per_minute": cl.RateLimitPerMinute,
		"created_at":            cl.CreatedAt,
	}))
}

type UpdateClientRequest struct {
	Name               string  `json:"name"`
	Description        *string `json:"description"`
	IsActive           bool    `json:"is_active"`
	RateLimitPerMinute *int    `json:"rate_limit_per_minute"`
}

func (s *Server) handleUpdateClient(c *gin.Context) {
	id := c.Param("id")
	var req UpdateClientRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse("Invalid request"))
		return
	}

	_, err := s.database.Exec(`
		UPDATE clients SET 
			name = ?, 
			description = ?, 
			is_active = ?, 
			rate_limit_per_minute = COALESCE(?, rate_limit_per_minute),
			updated_at = CURRENT_TIMESTAMP
		WHERE client_id = ?
	`, req.Name, req.Description, req.IsActive, req.RateLimitPerMinute, id)

	if err != nil {
		c.JSON(http.StatusInternalServerError, ErrorResponse(err.Error()))
		return
	}

	c.JSON(http.StatusOK, SuccessResponse(gin.H{"message": "Client updated"}))
}

type CreateClientRequest struct {
	Name     string  `json:"name" binding:"required"`
	ClientID *string `json:"client_id"`
}

func (s *Server) handleCreateClient(c *gin.Context) {
	var req CreateClientRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse("Invalid request"))
		return
	}

	clientID := ""
	if req.ClientID != nil {
		clientID = *req.ClientID
	} else {
		clientID = "client-" + uuid.New().String()[:8]
	}

	_, err := s.database.Exec("INSERT INTO clients (client_id, name, is_active) VALUES (?, ?, 1)", clientID, req.Name)
	if err != nil {
		c.JSON(http.StatusInternalServerError, ErrorResponse(err.Error()))
		return
	}

	token := "sk-" + uuid.New().String() + uuid.New().String()
	token = token[:51]

	_, err = s.database.Exec("INSERT INTO client_tokens (client_id, token, name) VALUES (?, ?, 'default')", clientID, token)
	if err != nil {
		// Log error
	}

	c.JSON(http.StatusOK, SuccessResponse(gin.H{
		"id":         clientID,
		"name":       req.Name,
		"status":     "active",
		"token":      token,
		"created_at": time.Now(),
	}))
}

func (s *Server) handleDeleteClient(c *gin.Context) {
	id := c.Param("id")
	if id == "default" {
		c.JSON(http.StatusBadRequest, ErrorResponse("Cannot delete default client"))
		return
	}

	_, err := s.database.Exec("DELETE FROM clients WHERE client_id = ?", id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, ErrorResponse(err.Error()))
		return
	}

	c.JSON(http.StatusOK, SuccessResponse(gin.H{"message": "Client deleted"}))
}

func (s *Server) handleGetClientTokens(c *gin.Context) {
	id := c.Param("id")
	var tokens []db.ClientToken
	err := s.database.Select(&tokens, "SELECT * FROM client_tokens WHERE client_id = ? ORDER BY created_at DESC", id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, ErrorResponse(err.Error()))
		return
	}

	type MaskedToken struct {
		ID          int        `json:"id"`
		TokenMasked string     `json:"token_masked"`
		Name        string     `json:"name"`
		IsActive    bool       `json:"is_active"`
		CreatedAt   time.Time  `json:"created_at"`
		LastUsedAt  *time.Time `json:"last_used_at"`
	}

	masked := make([]MaskedToken, len(tokens))
	for i, t := range tokens {
		maskedToken := "••••"
		if len(t.Token) > 8 {
			maskedToken = t.Token[:3] + "••••" + t.Token[len(t.Token)-8:]
		}
		masked[i] = MaskedToken{
			ID:          t.ID,
			TokenMasked: maskedToken,
			Name:        t.Name,
			IsActive:    t.IsActive,
			CreatedAt:   t.CreatedAt,
			LastUsedAt:  t.LastUsedAt,
		}
	}

	c.JSON(http.StatusOK, SuccessResponse(masked))
}

type CreateTokenRequest struct {
	Name string `json:"name"`
}

func (s *Server) handleCreateClientToken(c *gin.Context) {
	clientID := c.Param("id")
	var req CreateTokenRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		// optional name
	}

	name := "default"
	if req.Name != "" {
		name = req.Name
	}

	token := "sk-" + uuid.New().String() + uuid.New().String()
	token = token[:51]

	_, err := s.database.Exec("INSERT INTO client_tokens (client_id, token, name) VALUES (?, ?, ?)", clientID, token, name)
	if err != nil {
		c.JSON(http.StatusInternalServerError, ErrorResponse(err.Error()))
		return
	}

	c.JSON(http.StatusOK, SuccessResponse(gin.H{
		"token":      token,
		"name":       name,
		"created_at": time.Now(),
	}))
}

func (s *Server) handleDeleteClientToken(c *gin.Context) {
	tokenID := c.Param("token_id")

	_, err := s.database.Exec("DELETE FROM client_tokens WHERE id = ?", tokenID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, ErrorResponse(err.Error()))
		return
	}

	c.JSON(http.StatusOK, SuccessResponse(gin.H{"message": "Token revoked"}))
}
