package auth

import (
	"net/http"

	"photum-backend/internal/profissionais"

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

type Handler struct {
	service *Service
}

func NewHandler(service *Service) *Handler {
	return &Handler{service: service}
}

type registerRequest struct {
	Email            string                                 `json:"email" binding:"required,email"`
	Senha            string                                 `json:"senha" binding:"required,min=6"`
	Role             string                                 `json:"role" binding:"required,oneof=profissional empresa"`
	ProfissionalData *profissionais.CreateProfissionalInput `json:"profissional_data"`
}

// Register godoc
// @Summary      Register a new user
// @Description  Register a new user with optional professional profile
// @Tags         auth
// @Accept       json
// @Produce      json
// @Param        request body registerRequest true "Register Request"
// @Success      201  {object}  map[string]string
// @Failure      400  {object}  map[string]string
// @Failure      500  {object}  map[string]string
// @Router       /auth/register [post]
func (h *Handler) Register(c *gin.Context) {
	var req registerRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if req.Role == "profissional" && req.ProfissionalData == nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "profissional_data is required for role 'profissional'"})
		return
	}

	_, err := h.service.Register(c.Request.Context(), req.Email, req.Senha, req.Role, req.ProfissionalData)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, gin.H{"message": "user created"})
}

type loginRequest struct {
	Email string `json:"email" binding:"required,email"`
	Senha string `json:"senha" binding:"required"`
}

type loginResponse struct {
	AccessToken  string       `json:"access_token"`
	ExpiresAt    string       `json:"expires_at"`
	User         userResponse `json:"user"`
	Profissional interface{}  `json:"profissional,omitempty"`
}

type userResponse struct {
	ID    string `json:"id"`
	Email string `json:"email"`
	Role  string `json:"role"`
}

// Login godoc
// @Summary      Login
// @Description  Login with email and password
// @Tags         auth
// @Accept       json
// @Produce      json
// @Param        request body loginRequest true "Login Request"
// @Success      200  {object}  loginResponse
// @Failure      401  {object}  map[string]string
// @Failure      500  {object}  map[string]string
// @Router       /auth/login [post]
func (h *Handler) Login(c *gin.Context) {
	var req loginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	tokenPair, user, profData, err := h.service.Login(c.Request.Context(), req.Email, req.Senha)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
		return
	}

	http.SetCookie(c.Writer, &http.Cookie{
		Name:     "refresh_token",
		Value:    tokenPair.RefreshToken,
		Path:     "/auth/refresh",
		HttpOnly: true,
		Secure:   false,
		SameSite: http.SameSiteStrictMode,
		MaxAge:   30 * 24 * 60 * 60,
	})

	resp := loginResponse{
		AccessToken: tokenPair.AccessToken,
		ExpiresAt:   "2025-...",
		User: userResponse{
			ID:    uuid.UUID(user.ID.Bytes).String(),
			Email: user.Email,
			Role:  user.Role,
		},
	}

	if profData != nil {
		resp.Profissional = map[string]interface{}{
			"id":                     uuid.UUID(profData.ID.Bytes).String(),
			"nome":                   profData.Nome,
			"funcao_profissional_id": uuid.UUID(profData.FuncaoProfissionalID.Bytes).String(),
			"funcao_profissional":    profData.FuncaoNome.String,
			"equipamentos":           profData.Equipamentos.String,
		}
	}

	c.JSON(http.StatusOK, resp)
}

// Refresh and Logout handlers should be kept or restored if they were lost.
// I will assume they are needed and add them back in a subsequent edit if missing,
// or include them here if I can fit them.
// The previous content had them. I'll add them to be safe.

// Refresh godoc
// @Summary      Refresh access token
// @Description  Get a new access token using a valid refresh token
// @Tags         auth
// @Accept       json
// @Produce      json
// @Param        refresh_token body string false "Refresh Token"
// @Success      200  {object}  map[string]interface{}
// @Failure      401  {object}  map[string]string
// @Router       /auth/refresh [post]
func (h *Handler) Refresh(c *gin.Context) {
	refreshToken, err := c.Cookie("refresh_token")
	if err != nil {
		var req struct {
			RefreshToken string `json:"refresh_token"`
		}
		if err := c.ShouldBindJSON(&req); err == nil {
			refreshToken = req.RefreshToken
		}
	}

	if refreshToken == "" {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "refresh token required"})
		return
	}

	accessToken, accessExp, err := h.service.Refresh(c.Request.Context(), refreshToken)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid refresh token"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"access_token": accessToken,
		"expires_at":   accessExp,
	})
}

// Logout godoc
// @Summary      Logout user
// @Description  Revoke refresh token and clear cookie
// @Tags         auth
// @Accept       json
// @Produce      json
// @Param        refresh_token body string false "Refresh Token"
// @Success      200  {object}  map[string]string
// @Router       /auth/logout [post]
func (h *Handler) Logout(c *gin.Context) {
	refreshToken, err := c.Cookie("refresh_token")
	if err != nil {
		var req struct {
			RefreshToken string `json:"refresh_token"`
		}
		if err := c.ShouldBindJSON(&req); err == nil {
			refreshToken = req.RefreshToken
		}
	}

	if refreshToken != "" {
		_ = h.service.Logout(c.Request.Context(), refreshToken)
	}

	c.SetCookie("refresh_token", "", -1, "/", "", false, true)
	c.JSON(http.StatusOK, gin.H{"message": "logged out"})
}
