package account

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"strconv"

	"api_yal/internal/logger"
	"api_yal/internal/middleware"

	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
)

// AccountHandler обработчик для операций с аккаунтами
type AccountHandler struct {
	service   AccountService
	validator *validator.Validate
}

// NewHandler создает новый экземпляр Handler
func NewHandler(service AccountService) *AccountHandler {
	return &AccountHandler{
		service:   service,
		validator: validator.New(),
	}
}

// GetAccountByID получение аккаунта по ID
func (h *AccountHandler) GetAccountByID(w http.ResponseWriter, r *http.Request) {
	l := logger.Get()
	
	// Получаем ID из контекста (для своего профиля)
	userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
	if !ok {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}
	
	// Проверяем, что пользователь запрашивает свой профиль
	// В реальном приложении админы могут просматривать чужие профили
	account, err := h.service.GetAccountByID(userID)
	if err != nil {
		l.Error("Ошибка получения аккаунта", zap.Error(err))
		
		if errors.Is(err, ErrAccountNotFound) {
			http.Error(w, "Account not found", http.StatusNotFound)
			return
		}
		
		http.Error(w, "Failed to get account", http.StatusInternalServerError)
		return
	}
	
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(account)
}

// GetAccountProfile получение профиля пользователя
func (h *AccountHandler) GetAccountProfile(w http.ResponseWriter, r *http.Request) {
	l := logger.Get()
	
	userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
	if !ok {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}
	
	profile, err := h.service.GetAccountProfile(userID)
	if err != nil {
		l.Error("Ошибка получения профиля", zap.Error(err))
		
		if errors.Is(err, ErrAccountNotFound) {
			http.Error(w, "Account not found", http.StatusNotFound)
			return
		}
		
		http.Error(w, "Failed to get profile", http.StatusInternalServerError)
		return
	}
	
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(profile)
}

// UpdateAccount обновление аккаунта
func (h *AccountHandler) UpdateAccount(w http.ResponseWriter, r *http.Request) {
	l := logger.Get()
	
	userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
	if !ok {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}
	
	var req UpdateAccountRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}
	
	// Валидация не требуется для всех полей, так как они опциональны
	account, err := h.service.UpdateAccount(userID, req)
	if err != nil {
		l.Error("Ошибка обновления аккаунта", zap.Error(err))
		
		if errors.Is(err, ErrAccountNotFound) {
			http.Error(w, "Account not found", http.StatusNotFound)
			return
		}
		
		http.Error(w, "Failed to update account", http.StatusInternalServerError)
		return
	}
	
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(account)
}

// ChangePassword смена пароля
func (h *AccountHandler) ChangePassword(w http.ResponseWriter, r *http.Request) {
	l := logger.Get()
	
	userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
	if !ok {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}
	
	var req ChangePasswordRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}
	
	if err := h.validator.Struct(req); err != nil {
		h.handleValidationError(w, err)
		return
	}
	
	if err := h.service.ChangePassword(userID, req); err != nil {
		l.Error("Ошибка смены пароля", zap.Error(err))
		
		if errors.Is(err, ErrInvalidCurrentPassword) {
			http.Error(w, "Current password is incorrect", http.StatusBadRequest)
			return
		}
		
		if errors.Is(err, ErrAccountNotFound) {
			http.Error(w, "Account not found", http.StatusNotFound)
			return
		}
		
		http.Error(w, "Failed to change password", http.StatusInternalServerError)
		return
	}
	
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]string{
		"message": "Password changed successfully",
	})
}

// DeleteAccount удаление аккаунта
func (h *AccountHandler) DeleteAccount(w http.ResponseWriter, r *http.Request) {
	l := logger.Get()
	
	userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
	if !ok {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}
	
	if err := h.service.DeleteAccount(userID); err != nil {
		l.Error("Ошибка удаления аккаунта", zap.Error(err))
		
		if errors.Is(err, ErrAccountNotFound) {
			http.Error(w, "Account not found", http.StatusNotFound)
			return
		}
		
		http.Error(w, "Failed to delete account", http.StatusInternalServerError)
		return
	}
	
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]string{
		"message": "Account deleted successfully",
	})
}

// ==================== Административные методы ====================

// ListAccounts список аккаунтов (админ)
func (h *AccountHandler) ListAccounts(w http.ResponseWriter, r *http.Request) {
	l := logger.Get()
	
	var req ListAccountsRequest
	
	// Парсинг query параметров
	if pageStr := r.URL.Query().Get("page"); pageStr != "" {
		page, _ := strconv.Atoi(pageStr)
		req.Page = page
	}
	if pageSizeStr := r.URL.Query().Get("page_size"); pageSizeStr != "" {
		pageSize, _ := strconv.Atoi(pageSizeStr)
		req.PageSize = pageSize
	}
	req.Search = r.URL.Query().Get("search")
	req.Role = r.URL.Query().Get("role")
	if isActiveStr := r.URL.Query().Get("is_active"); isActiveStr != "" {
		isActive, _ := strconv.ParseBool(isActiveStr)
		req.IsActive = &isActive
	}
	
	if err := h.validator.Struct(req); err != nil {
		h.handleValidationError(w, err)
		return
	}
	
	response, err := h.service.ListAccounts(req)
	if err != nil {
		l.Error("Ошибка получения списка аккаунтов", zap.Error(err))
		http.Error(w, "Failed to list accounts", http.StatusInternalServerError)
		return
	}
	
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(response)
}

// GetAccountByIDAdmin получение аккаунта по ID (админ)
func (h *AccountHandler) GetAccountByIDAdmin(w http.ResponseWriter, r *http.Request) {
	l := logger.Get()
	
	// Получаем ID из URL
	idStr := r.URL.Query().Get("id")
	if idStr == "" {
		http.Error(w, "Missing id parameter", http.StatusBadRequest)
		return
	}
	
	id, err := strconv.ParseUint(idStr, 10, 32)
	if err != nil {
		http.Error(w, "Invalid id parameter", http.StatusBadRequest)
		return
	}
	
	account, err := h.service.GetAccountByID(uint(id))
	if err != nil {
		l.Error("Ошибка получения аккаунта", zap.Error(err))
		
		if errors.Is(err, ErrAccountNotFound) {
			http.Error(w, "Account not found", http.StatusNotFound)
			return
		}
		
		http.Error(w, "Failed to get account", http.StatusInternalServerError)
		return
	}
	
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(account)
}

// VerifyAccount верификация аккаунта (админ)
func (h *AccountHandler) VerifyAccount(w http.ResponseWriter, r *http.Request) {
	l := logger.Get()
	
	// Получаем ID из URL
	idStr := r.URL.Query().Get("id")
	if idStr == "" {
		http.Error(w, "Missing id parameter", http.StatusBadRequest)
		return
	}
	
	id, err := strconv.ParseUint(idStr, 10, 32)
	if err != nil {
		http.Error(w, "Invalid id parameter", http.StatusBadRequest)
		return
	}
	
	var req VerifyAccountRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}
	
	if err := h.service.VerifyAccount(uint(id), req); err != nil {
		l.Error("Ошибка верификации аккаунта", zap.Error(err))
		
		if errors.Is(err, ErrAccountNotFound) {
			http.Error(w, "Account not found", http.StatusNotFound)
			return
		}
		
		http.Error(w, "Failed to verify account", http.StatusInternalServerError)
		return
	}
	
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]string{
		"message": "Account verified successfully",
	})
}

// UpdateAccountStatus обновление статуса аккаунта (админ)
func (h *AccountHandler) UpdateAccountStatus(w http.ResponseWriter, r *http.Request) {
	l := logger.Get()
	
	// Получаем ID из URL
	idStr := r.URL.Query().Get("id")
	if idStr == "" {
		http.Error(w, "Missing id parameter", http.StatusBadRequest)
		return
	}
	
	id, err := strconv.ParseUint(idStr, 10, 32)
	if err != nil {
		http.Error(w, "Invalid id parameter", http.StatusBadRequest)
		return
	}
	
	var req UpdateAccountStatusRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}
	
	if err := h.validator.Struct(req); err != nil {
		h.handleValidationError(w, err)
		return
	}
	
	if err := h.service.UpdateAccountStatus(uint(id), req); err != nil {
		l.Error("Ошибка обновления статуса аккаунта", zap.Error(err))
		
		if errors.Is(err, ErrAccountNotFound) {
			http.Error(w, "Account not found", http.StatusNotFound)
			return
		}
		
		http.Error(w, "Failed to update account status", http.StatusInternalServerError)
		return
	}
	
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]string{
		"message": "Account status updated successfully",
	})
}

// handleValidationError обрабатывает ошибки валидации
func (h *AccountHandler) handleValidationError(w http.ResponseWriter, err error) {
	var invalidValidationError *validator.InvalidValidationError
	if errors.As(err, &invalidValidationError) {
		http.Error(w, "Invalid request", http.StatusBadRequest)
		return
	}
	
	var errs []string
	for _, err := range err.(validator.ValidationErrors) {
		errs = append(errs, fmt.Sprintf("field %s is invalid: %s", err.Field(), err.Tag()))
	}
	
	w.WriteHeader(http.StatusBadRequest)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"error":  "Validation failed",
		"fields": errs,
	})
}