package lkgateway

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

	"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/m2mcore"
)

// RegisterAPI вешает REST-маршруты ESIA Finance V1 на mux.
func RegisterAPI(mux *http.ServeMux, svc *Service) {
	mux.HandleFunc("/api/v1/back_office/claims/", func(w http.ResponseWriter, r *http.Request) {
		path := strings.TrimPrefix(r.URL.Path, "/api/v1/back_office/claims/")
		switch {
		case path == "" && r.Method == http.MethodPost:
			handleCreateClaim(w, r, svc)
		case path != "" && r.Method == http.MethodGet:
			handleGetClaim(w, r, svc, path)
		case path != "" && r.Method == http.MethodPatch:
			// PATCH без id — отдельный обработчик ниже; этот блок для PATCH
			// с id, который lk-gateway сам себе бы посылал. На практике не
			// используется (callback идёт в ЛК), но реализуем по контракту.
			handlePatchClaim(w, r, svc, path)
		default:
			writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Метод не разрешён", r.Method)
		}
	})

	mux.HandleFunc("/api/v1/back_office/claims", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodGet {
			writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Метод не разрешён", r.Method)
			return
		}
		handleListClaims(w, r, svc)
	})
}

func handleCreateClaim(w http.ResponseWriter, r *http.Request, svc *Service) {
	defer r.Body.Close()
	var in CreateClaimRequest
	if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
		writeError(w, http.StatusBadRequest, "invalid_json", "Не смогли разобрать JSON", err.Error())
		return
	}
	out, err := svc.CreateClaim(r.Context(), in)
	if err != nil {
		writeError(w, http.StatusUnprocessableEntity, "invalid_claim", "Заявка не прошла валидацию", err.Error())
		return
	}
	writeJSON(w, http.StatusCreated, out)
}

func handleGetClaim(w http.ResponseWriter, r *http.Request, svc *Service, id string) {
	view, err := svc.GetClaim(r.Context(), id)
	if err != nil {
		if errors.Is(err, m2mcore.ErrNotFound) {
			writeError(w, http.StatusNotFound, "not_found", "Заявка не найдена", id)
			return
		}
		writeError(w, http.StatusInternalServerError, "internal", "Внутренняя ошибка", err.Error())
		return
	}
	writeJSON(w, http.StatusOK, view)
}

func handleListClaims(w http.ResponseWriter, r *http.Request, svc *Service) {
	q := r.URL.Query()
	filter := m2mcore.Filter{}
	if s := q.Get("status"); s != "" {
		st := m2mcore.State(s)
		filter.State = &st
	}
	if inv := q.Get("investor_id"); inv != "" {
		filter.InvestorID = inv
	}
	if l := q.Get("limit"); l != "" {
		if n, err := strconv.Atoi(l); err == nil && n > 0 && n <= 200 {
			filter.Limit = n
		}
	}
	if o := q.Get("offset"); o != "" {
		if n, err := strconv.Atoi(o); err == nil && n >= 0 {
			filter.Offset = n
		}
	}
	page, err := svc.ListClaims(r.Context(), filter)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "internal", "Внутренняя ошибка", err.Error())
		return
	}
	writeJSON(w, http.StatusOK, page)
}

func handlePatchClaim(w http.ResponseWriter, _ *http.Request, _ *Service, _ string) {
	// В сценарии M1-M2 PATCH /claims/{id} от внешней системы (как
	// callback от НРД) не используется — мы сами шлём callback в ЛК.
	// Но оставляем заглушку с 200, чтобы покрыть контракт OpenAPI.
	writeJSON(w, http.StatusOK, map[string]bool{"success": true})
}
