package http_router

import (
	"context"
	"encoding/json"
	"io"
	"log/slog"
	"net/http"

	"git-molva.ru/Molva/molva-backend/services/api_gateway/internal/constants"
	rmodel "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/request_model"
	"github.com/gorilla/mux"
)

// @Summary Получить баланс агента
// @Description Получение текущего баланса агента
// @Tags agents
// @Accept json
// @Produce json
// @Param agent_id path string true "ID агента"
// @Success 200 {object} rmodel.BalanceGetResponse "Баланс агента"
// @Failure 400 {object} map[string]string "Неверные параметры запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/agents/{agent_id}/balance [get]
func (h *handler) getBalanceAgentHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "getBalanceAgentHandler"

	var (
		vars    = mux.Vars(r)
		agentId = vars["agent_id"]
	)

	result, err := h.agentService.GetBalance(r.Context(), &rmodel.BalanceGetRequest{
		OwnerId: agentId,
	})
	if err != nil {
		h.handleAgentError(w, err)
		h.logger.Error("error getting balance info",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Получить список транзакций агента
// @Description Получение списка транзакций агента с возможностью фильтрации
// @Tags agents
// @Accept json
// @Produce json
// @Param agent_id path string true "ID агента"
// @Success 200 {object} rmodel.TransactionListGetResponse "Список транзакций"
// @Failure 400 {object} map[string]string "Неверные параметры запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/agents/{agent_id}/transactions [get]
func (h *handler) getTransactionListAgentHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "getTransactionListAgentHandler"

	var (
		vars    = mux.Vars(r)
		agentId = vars["agent_id"]
	)

	request, err := new(rmodel.TransactionListGetRequest).FromQuery(r.URL.Query())
	if err != nil {
		http.Error(w, constants.ErrBadRequest.Error(), http.StatusBadRequest)
		h.logger.Error("error parsing request: ",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName))

		return
	}

	request.OwnerId = agentId

	result, err := h.agentService.GetTransactionList(r.Context(), request)
	if err != nil {
		h.handleAgentError(w, err)
		h.logger.Error("error getting transactions",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Создать транзакцию агента
// @Description Создание новой транзакции для агента
// @Tags agents
// @Accept json
// @Produce json
// @Param agent_id path string true "ID агента"
// @Param request body rmodel.TransactionCreateRequest true "Данные транзакции"
// @Success 201 {object} rmodel.TransactionCreateResponse "Транзакция создана"
// @Failure 400 {object} map[string]string "Неверные данные запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/agents/{agent_id}/transactions [post]
func (h *handler) createTransactionAgentHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "createTransactionAgentHandler"

	var (
		vars    = mux.Vars(r)
		agentId = vars["agent_id"]
	)

	var request rmodel.TransactionCreateRequest
	if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
		http.Error(w, constants.ErrBadRequest.Error(), http.StatusBadRequest)
		h.logger.Error("error while unmarshalling request: ",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName))

		return
	}

	defer func(body io.ReadCloser) {
		if err := body.Close(); err != nil {
			http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
			h.logger.Error("error closing body",
				slog.String("error", err.Error()),
				slog.String("handler", handlerName))
		}
	}(r.Body)

	request.OwnerId = agentId

	result, err := h.agentService.CreateTransaction(r.Context(), &request)
	if err != nil {
		h.handleAgentError(w, err)
		h.logger.Error("error creating transaction",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	// TODO: fix feed event
	// go h.createTransactionFeedEvent(
	// 	context.Background(),
	// 	agentId,
	// 	true,
	// 	request.Amount,
	// 	request.Currency,
	// 	request.BankAccountId,
	// 	handlerName,
	// )

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Получить список банковских счетов агента
// @Description Получение списка банковских счетов агента
// @Tags agents
// @Accept json
// @Produce json
// @Param agent_id path string true "ID агента"
// @Success 200 {object} rmodel.BankAccountListGetResponse "Список банковских счетов"
// @Failure 400 {object} map[string]string "Неверные параметры запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/agents/{agent_id}/bank_accounts [get]
func (h *handler) getBankAccountListAgentHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "getBankAccountListAgentHandler"

	var (
		vars    = mux.Vars(r)
		agentId = vars["agent_id"]
	)

	result, err := h.agentService.GetBankAccountList(r.Context(), &rmodel.BankAccountListGetRequest{
		OwnerId: agentId,
	})
	if err != nil {
		h.handleAgentError(w, err)
		h.logger.Error("error getting bank accounts",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Создать банковский счет агента
// @Description Создание нового банковского счета для агента
// @Tags agents
// @Accept json
// @Produce json
// @Param agent_id path string true "ID агента"
// @Param request body rmodel.BankAccountCreateRequest true "Данные банковского счета"
// @Success 201 {object} rmodel.BankAccountCreateResponse "Банковский счет создан"
// @Failure 400 {object} map[string]string "Неверные данные запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/agents/{agent_id}/bank_accounts [post]
func (h *handler) createBankAccountAgentHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "createBankAccountAgentHandler"

	var (
		vars    = mux.Vars(r)
		agentId = vars["agent_id"]
	)

	var request rmodel.BankAccountCreateRequest
	if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
		http.Error(w, constants.ErrBadRequest.Error(), http.StatusBadRequest)
		h.logger.Error("error while unmarshalling request: ",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName))

		return
	}

	defer func(body io.ReadCloser) {
		if err := body.Close(); err != nil {
			http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
			h.logger.Error("error closing body",
				slog.String("error", err.Error()),
				slog.String("handler", handlerName))
		}
	}(r.Body)

	request.OwnerId = agentId

	result, err := h.agentService.CreateBankAccount(r.Context(), &request)
	if err != nil {
		h.handleAgentError(w, err)
		h.logger.Error("error creating bank account",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	// FIXME: possible nil dereference
	// h.createCreateBankAccountFeedEvent(r.Context(), agentId, true, resp, *request.BankName, handlerName)

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Обновить банковский счет агента
// @Description Обновление информации о банковском счете агента
// @Tags agents
// @Accept json
// @Produce json
// @Param agent_id path string true "ID агента"
// @Param bank_account_id path string true "ID банковского счета"
// @Param request body rmodel.BankAccountUpdateRequest true "Данные для обновления"
// @Success 200 {object} map[string]string "Банковский счет обновлен"
// @Failure 400 {object} map[string]string "Неверные данные запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/agents/{agent_id}/bank_accounts/{bank_account_id} [put]
func (h *handler) updateBankAccountAgentHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "updateBankAccountAgentHandler"

	var (
		vars          = mux.Vars(r)
		agentId       = vars["agent_id"]
		bankAccountId = vars["bank_account_id"]
	)

	var request rmodel.BankAccountUpdateRequest
	if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
		http.Error(w, constants.ErrBadRequest.Error(), http.StatusBadRequest)
		h.logger.Error("error while unmarshalling request: ",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName))

		return
	}

	defer func(body io.ReadCloser) {
		if err := body.Close(); err != nil {
			http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
			h.logger.Error("error closing body",
				slog.String("error", err.Error()),
				slog.String("handler", handlerName))
		}
	}(r.Body)

	request.Id = bankAccountId
	request.OwnerId = agentId

	if _, err := h.agentService.UpdateBankAccount(r.Context(), &request); err != nil {
		h.handleAgentError(w, err)
		h.logger.Error("error editing bank account",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	go h.createEditBankAccountFeedEvent(
		context.Background(),
		agentId,
		true,
		bankAccountId,
		handlerName,
	)

	w.WriteHeader(http.StatusNoContent)
}

// TODO: test when implemented
// @Summary Удалить банковский счет агента
// @Description Удаление банковского счета агента
// @Tags agents
// @Accept json
// @Produce json
// @Param agent_id path string true "ID агента"
// @Param bank_account_id path string true "ID банковского счета"
// @Success 200 {object} map[string]string "Банковский счет удален"
// @Failure 400 {object} map[string]string "Неверные параметры запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/agents/{agent_id}/bank_accounts/{bank_account_id} [delete]
func (h *handler) deleteBankAccountAgentHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "deleteBankAccountAgentHandler"

	var (
		vars          = mux.Vars(r)
		agentId       = vars["agent_id"]
		bankAccountId = vars["bank_account_id"]
	)

	result, err := h.agentService.DeleteBankAccount(r.Context(), &rmodel.BankAccountDeleteRequest{
		Id:      bankAccountId,
		OwnerId: agentId,
	})
	if err != nil {
		h.handleAgentError(w, err)
		h.logger.Error("error deleting bank account",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	go func() {
		if err := h.feed.CancelEvent(context.Background(), bankAccountId, "Банковский счёт удален"); err != nil {
			h.logger.Error("error cancelling event: ",
				slog.String("error", err.Error()),
				slog.String("handler", handlerName))
		}
	}()

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Получить баланс дистрибьютора
// @Description Получение текущего баланса дистрибьютора
// @Tags distributors
// @Accept json
// @Produce json
// @Param distributor_id path string true "ID дистрибьютора"
// @Success 200 {object} rmodel.BalanceGetResponse "Баланс дистрибьютора"
// @Failure 400 {object} map[string]string "Неверные параметры запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/distributor/{distributor_id}/balance [get]
func (h *handler) getBalanceDistributorHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "getBalanceDistributorHandler"

	var (
		vars   = mux.Vars(r)
		distId = vars["distributor_id"]
	)

	result, err := h.distributorService.GetBalance(r.Context(), &rmodel.BalanceGetRequest{
		OwnerId: distId,
	})
	if err != nil {
		h.handleDistributorError(w, err)
		h.logger.Error("error getting balance",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Получить баланс компании дистрибьютора
// @Description Получение баланса конкретной компании дистрибьютора
// @Tags distributors
// @Accept json
// @Produce json
// @Param distributor_id path string true "ID дистрибьютора"
// @Param company_id path string true "ID компании"
// @Success 200 {object} rmodel.BalanceGetResponse "Баланс компании"
// @Failure 400 {object} map[string]string "Неверные параметры запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/distributor/{distributor_id}/company/{company_id}/balance [get]
func (h *handler) getCompanyBalanceDistributorHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "getCompanyBalanceDistributorHandler"

	var (
		vars      = mux.Vars(r)
		companyId = vars["company_id"]
	)

	result, err := h.distributorService.GetBalance(r.Context(), &rmodel.BalanceGetRequest{
		OwnerId: companyId,
	})
	if err != nil {
		h.handleDistributorError(w, err)
		h.logger.Error("error getting balance",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Получить список транзакций дистрибьютора
// @Description Получение списка транзакций дистрибьютора с возможностью фильтрации
// @Tags distributors
// @Accept json
// @Produce json
// @Param distributor_id path string true "ID дистрибьютора"
// @Success 200 {object} rmodel.TransactionListGetResponse "Список транзакций"
// @Failure 400 {object} map[string]string "Неверные параметры запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/distributor/{distributor_id}/transactions [get]
func (h *handler) getTransactionListDistributorHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "getTransactionListDistributorHandler"

	var (
		vars   = mux.Vars(r)
		distId = vars["distributor_id"]
	)

	request, err := new(rmodel.TransactionListGetRequest).FromQuery(r.URL.Query())
	if err != nil {
		http.Error(w, constants.ErrBadRequest.Error(), http.StatusBadRequest)
		h.logger.Error("error parsing request: ",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	request.OwnerId = distId

	result, err := h.distributorService.GetTransactionList(r.Context(), request)
	if err != nil {
		h.handleDistributorError(w, err)
		h.logger.Error("error getting transactions",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Получить список транзакций компании дистрибьютора
// @Description Получение списка транзакций конкретной компании дистрибьютора
// @Tags distributors
// @Accept json
// @Produce json
// @Param distributor_id path string true "ID дистрибьютора"
// @Param company_id path string true "ID компании"
// @Success 200 {object} rmodel.TransactionListGetResponse "Список транзакций компании"
// @Failure 400 {object} map[string]string "Неверные параметры запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/distributor/{distributor_id}/company/{company_id}/transactions [get]
func (h *handler) getCompanyTransactionListDistributorHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "getCompanyTransactionListDistributorHandler"

	var (
		vars      = mux.Vars(r)
		companyId = vars["company_id"]
	)

	request, err := new(rmodel.TransactionListGetRequest).FromQuery(r.URL.Query())
	if err != nil {
		http.Error(w, constants.ErrBadRequest.Error(), http.StatusBadRequest)
		h.logger.Error("error parsing request: ",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	request.OwnerId = companyId

	result, err := h.distributorService.GetTransactionList(r.Context(), request)
	if err != nil {
		h.handleDistributorError(w, err)
		h.logger.Error("error getting transactions",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Создать транзакцию дистрибьютора
// @Description Создание новой транзакции для дистрибьютора
// @Tags distributors
// @Accept json
// @Produce json
// @Param distributor_id path string true "ID дистрибьютора"
// @Param request body rmodel.TransactionCreateRequest true "Данные транзакции"
// @Success 201 {object} rmodel.TransactionCreateResponse "Транзакция создана"
// @Failure 400 {object} map[string]string "Неверные данные запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/distributor/{distributor_id}/transactions [post]
func (h *handler) createTransactionDistributorHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "createTransactionDistributorHandler"

	var (
		vars   = mux.Vars(r)
		distId = vars["distributor_id"]
	)

	var request rmodel.TransactionCreateRequest
	if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
		http.Error(w, constants.ErrBadRequest.Error(), http.StatusBadRequest)
		h.logger.Error("error while unmarshalling request: ",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName))

		return
	}

	defer func(body io.ReadCloser) {
		if err := body.Close(); err != nil {
			http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
			h.logger.Error("error closing body",
				slog.String("error", err.Error()),
				slog.String("handler", handlerName))
		}
	}(r.Body)

	request.OwnerId = distId

	result, err := h.distributorService.CreateTransaction(r.Context(), &request)
	if err != nil {
		h.handleDistributorError(w, err)
		h.logger.Error("error creating transaction",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	// TODO: fix feed event
	// go h.createTransactionFeedEvent(
	// 	context.Background(),
	// 	distId,
	// 	false,
	// 	request.Amount,
	// 	request.Currency,
	// 	request.BankAccountId,
	// 	handlerName,
	// )

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Получить список банковских счетов дистрибьютора
// @Description Получение списка банковских счетов дистрибьютора
// @Tags distributors
// @Accept json
// @Produce json
// @Param distributor_id path string true "ID дистрибьютора"
// @Success 200 {object} rmodel.BankAccountListGetResponse "Список банковских счетов"
// @Failure 400 {object} map[string]string "Неверные параметры запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/distributor/{distributor_id}/bank_accounts [get]
func (h *handler) getBankAccountListDistributorHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "getBankAccountListDistributorHandler"

	var (
		vars   = mux.Vars(r)
		distId = vars["distributor_id"]
	)

	result, err := h.distributorService.GetBankAccountList(r.Context(), &rmodel.BankAccountListGetRequest{
		OwnerId: distId,
	})
	if err != nil {
		h.handleDistributorError(w, err)
		h.logger.Error("error getting bank accounts",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Получить список банковских счетов компании дистрибьютора
// @Description Получение списка банковских счетов конкретной компании дистрибьютора
// @Tags distributors
// @Accept json
// @Produce json
// @Param distributor_id path string true "ID дистрибьютора"
// @Param company_id path string true "ID компании"
// @Success 200 {object} rmodel.BankAccountListGetResponse "Список банковских счетов компании"
// @Failure 400 {object} map[string]string "Неверные параметры запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/distributor/{distributor_id}/company/{company_id}/bank_accounts [get]
func (h *handler) getCompanyBankAccountListDistributorHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "getCompanyBankAccountListDistributorHandler"

	var (
		vars      = mux.Vars(r)
		companyId = vars["company_id"]
	)

	result, err := h.distributorService.GetBankAccountList(r.Context(), &rmodel.BankAccountListGetRequest{
		OwnerId: companyId,
	})
	if err != nil {
		h.handleDistributorError(w, err)
		h.logger.Error("error getting bank accounts",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Создать банковский счет компании дистрибьютора
// @Description Создание нового банковского счета для компании дистрибьютора
// @Tags distributors
// @Accept json
// @Produce json
// @Param distributor_id path string true "ID дистрибьютора"
// @Param company_id path string true "ID компании"
// @Param request body rmodel.BankAccountCreateRequest true "Данные банковского счета"
// @Success 201 {object} rmodel.BankAccountCreateResponse "Банковский счет создан"
// @Failure 400 {object} map[string]string "Неверные данные запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/distributor/{distributor_id}/company/{company_id}/bank_accounts [post]
func (h *handler) createBankAccountDistributorHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "createBankAccountDistributorHandler"

	var (
		vars      = mux.Vars(r)
		companyId = vars["company_id"]
	)

	var request rmodel.BankAccountCreateRequest
	if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
		http.Error(w, constants.ErrBadRequest.Error(), http.StatusBadRequest)
		h.logger.Error("error while unmarshalling request: ",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName))

		return
	}

	defer func(body io.ReadCloser) {
		if err := body.Close(); err != nil {
			http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
			h.logger.Error("error closing body",
				slog.String("error", err.Error()),
				slog.String("handler", handlerName))
		}
	}(r.Body)

	request.OwnerId = companyId

	result, err := h.distributorService.CreateBankAccount(r.Context(), &request)
	if err != nil {
		h.handleDistributorError(w, err)
		h.logger.Error("error creating bank account",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	// FIXME: possible nil dereference
	// go h.createCreateBankAccountFeedEvent(
	// 	context.Background(),
	// 	distId,
	// 	false,
	// 	resp,
	// 	*request.BankName,
	// 	handlerName,
	// )

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Обновить банковский счет дистрибьютора
// @Description Обновление информации о банковском счете дистрибьютора
// @Tags distributors
// @Accept json
// @Produce json
// @Param distributor_id path string true "ID дистрибьютора"
// @Param bank_account_id path string true "ID банковского счета"
// @Param request body rmodel.BankAccountUpdateRequest true "Данные для обновления"
// @Success 200 {object} map[string]string "Банковский счет обновлен"
// @Failure 400 {object} map[string]string "Неверные данные запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/distributor/{distributor_id}/bank_accounts/{bank_account_id} [put]
func (h *handler) updateBankAccountDistributorHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "updateBankAccountDistributorHandler"

	var (
		vars          = mux.Vars(r)
		distId        = vars["distributor_id"]
		bankAccountId = vars["bank_account_id"]
	)

	var request rmodel.BankAccountUpdateRequest
	if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
		http.Error(w, constants.ErrBadRequest.Error(), http.StatusBadRequest)
		h.logger.Error("error while unmarshalling request: ",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName))

		return
	}

	defer func(body io.ReadCloser) {
		if err := body.Close(); err != nil {
			http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
			h.logger.Error("error closing body",
				slog.String("error", err.Error()),
				slog.String("handler", handlerName))
		}
	}(r.Body)

	request.OwnerId = distId
	request.Id = bankAccountId

	result, err := h.distributorService.UpdateBankAccount(r.Context(), &request)
	if err != nil {
		h.handleDistributorError(w, err)
		h.logger.Error("error editing bank account",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	go h.createEditBankAccountFeedEvent(
		context.Background(),
		distId,
		true,
		bankAccountId,
		handlerName,
	)

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}

// @Summary Удалить банковский счет дистрибьютора
// @Description Удаление банковского счета дистрибьютора
// @Tags distributors
// @Accept json
// @Produce json
// @Param distributor_id path string true "ID дистрибьютора"
// @Param bank_account_id path string true "ID банковского счета"
// @Success 200 {object} map[string]string "Банковский счет удален"
// @Failure 400 {object} map[string]string "Неверные параметры запроса"
// @Failure 500 {object} map[string]string "Внутренняя ошибка сервера"
// @Security BearerAuth
// @Router /api/v1/distributor/{distributor_id}/bank_accounts/{bank_account_id} [delete]
func (h *handler) deleteBankAccountDistributorHandler(w http.ResponseWriter, r *http.Request) {
	const handlerName = "deleteBankAccountDistributorHandler"

	var (
		vars          = mux.Vars(r)
		distId        = vars["distributor_id"]
		bankAccountId = vars["bank_account_id"]
	)

	result, err := h.distributorService.DeleteBankAccount(r.Context(), &rmodel.BankAccountDeleteRequest{
		Id:      bankAccountId,
		OwnerId: distId,
	})
	if err != nil {
		h.handleDistributorError(w, err)
		h.logger.Error("error deleting bank account",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)

		return
	}

	go func() {
		if err := h.feed.CancelEvent(context.Background(), bankAccountId, "Банковский счёт удален"); err != nil {
			http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
			h.logger.Error("error while cancelling event: ",
				slog.String("error", err.Error()),
				slog.String("handler", handlerName))
		}
	}()

	w.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(w).Encode(result); err != nil {
		http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError)
		h.logger.Error("error encoding response",
			slog.String("error", err.Error()),
			slog.String("handler", handlerName),
		)
	}
}
