package handler

import (
	"errors"
	"net/http"
	"strings"

	"github.com/gofrs/uuid/v5"
	"github.com/saveinmed/backend-go/internal/domain"
)

// CreateUser godoc
// @Summary Criar usuário
// @Tags Usuários
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param payload body createUserRequest true "Novo usuário"
// @Success 201 {object} domain.User
// @Failure 400 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/users [post]
func (h *Handler) CreateUser(w http.ResponseWriter, r *http.Request) {
	requester, err := getRequester(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	var req createUserRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	if strings.EqualFold(requester.Role, "Seller") {
		if requester.CompanyID == nil {
			writeError(w, http.StatusBadRequest, errors.New("seller must include X-Company-ID header"))
			return
		}
		if req.CompanyID != *requester.CompanyID {
			writeError(w, http.StatusForbidden, errors.New("seller can only manage their own company users"))
			return
		}
	}

	user := &domain.User{
		CompanyID: req.CompanyID,
		Role:      req.Role,
		Name:      req.Name,
		Username:  req.Username,
		Email:     req.Email,
	}

	if err := h.svc.CreateUser(r.Context(), user, req.Password); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusCreated, user)
}

// ListUsers godoc
// @Summary Listar usuários
// @Tags Usuários
// @Security BearerAuth
// @Produce json
// @Param page query int false "Página"
// @Param page_size query int false "Tamanho da página"
// @Param company_id query string false "Filtro por empresa"
// @Success 200 {object} domain.UserPage
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/users [get]
func (h *Handler) ListUsers(w http.ResponseWriter, r *http.Request) {
	requester, err := getRequester(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	page, pageSize := parsePagination(r)

	var companyFilter *uuid.UUID
	if cid := r.URL.Query().Get("company_id"); cid != "" {
		id, err := uuid.FromString(cid)
		if err != nil {
			writeError(w, http.StatusBadRequest, errors.New("invalid company_id"))
			return
		}
		companyFilter = &id
	}

	if strings.EqualFold(requester.Role, "Seller") {
		if requester.CompanyID == nil {
			writeError(w, http.StatusBadRequest, errors.New("seller must include X-Company-ID header"))
			return
		}
		companyFilter = requester.CompanyID
	}

	pageResult, err := h.svc.ListUsers(r.Context(), domain.UserFilter{CompanyID: companyFilter}, page, pageSize)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, pageResult)
}

// GetUser godoc
// @Summary Obter usuário
// @Tags Usuários
// @Security BearerAuth
// @Produce json
// @Param id path string true "User ID"
// @Success 200 {object} domain.User
// @Failure 400 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/v1/users/{id} [get]
func (h *Handler) GetUser(w http.ResponseWriter, r *http.Request) {
	requester, err := getRequester(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	user, err := h.svc.GetUser(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, err)
		return
	}

	if strings.EqualFold(requester.Role, "Seller") {
		if requester.CompanyID == nil || user.CompanyID != *requester.CompanyID {
			writeError(w, http.StatusForbidden, errors.New("seller can only view users from their company"))
			return
		}
	}

	writeJSON(w, http.StatusOK, user)
}

// UpdateUser godoc
// @Summary Atualizar usuário
// @Tags Usuários
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param id path string true "User ID"
// @Param payload body updateUserRequest true "Campos para atualização"
// @Success 200 {object} domain.User
// @Failure 400 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/users/{id} [put]
func (h *Handler) UpdateUser(w http.ResponseWriter, r *http.Request) {
	requester, err := getRequester(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	var req updateUserRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	user, err := h.svc.GetUser(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, err)
		return
	}

	if strings.EqualFold(requester.Role, "Seller") {
		if requester.CompanyID == nil || user.CompanyID != *requester.CompanyID {
			writeError(w, http.StatusForbidden, errors.New("seller can only update their company users"))
			return
		}
	}

	if req.CompanyID != nil {
		user.CompanyID = *req.CompanyID
	}
	if req.Role != nil {
		user.Role = *req.Role
	}
	if req.Name != nil {
		user.Name = *req.Name
	}
	if req.Username != nil {
		user.Username = *req.Username
	}
	if req.Email != nil {
		user.Email = *req.Email
	}

	newPassword := ""
	if req.Password != nil {
		newPassword = *req.Password
	}

	if err := h.svc.UpdateUser(r.Context(), user, newPassword); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, user)
}

// DeleteUser godoc
// @Summary Excluir usuário
// @Tags Usuários
// @Security BearerAuth
// @Param id path string true "User ID"
// @Success 204 {string} string "No Content"
// @Failure 400 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/users/{id} [delete]
func (h *Handler) DeleteUser(w http.ResponseWriter, r *http.Request) {
	requester, err := getRequester(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	user, err := h.svc.GetUser(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, err)
		return
	}

	if strings.EqualFold(requester.Role, "Seller") {
		if requester.CompanyID == nil || user.CompanyID != *requester.CompanyID {
			writeError(w, http.StatusForbidden, errors.New("seller can only delete their company users"))
			return
		}
	}

	if err := h.svc.DeleteUser(r.Context(), id); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}
