package api

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

	"github.com/gorilla/mux"
	"dejo_node/internal/dao"
)

type CreateProposalRequest struct {
	Title    string `json:"title"`
	Content  string `json:"content"`
	Type     string `json:"type"`
	Creator  string `json:"creator"`
	Duration int64  `json:"duration"`
}

type VoteRequest struct {
	Address string `json:"address"`
	Approve bool   `json:"approve"`
}

func (h *Handler) CreateProposal(w http.ResponseWriter, r *http.Request) {
	var req CreateProposalRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		WriteError(w, http.StatusBadRequest, "JSON inválido")
		return
	}
	p := DaoStore.Create(req.Title, req.Content, req.Creator, dao.ProposalType(req.Type), req.Duration)
	_ = DaoStore.SaveToDisk("data/proposals.db")
	WriteJSON(w, p)
}

func (h *Handler) VoteProposal(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["id"]
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		WriteError(w, http.StatusBadRequest, "ID inválido")
		return
	}
	var req VoteRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		WriteError(w, http.StatusBadRequest, "JSON inválido")
		return
	}
	p, err := DaoStore.Get(id)
	if err != nil {
		WriteError(w, http.StatusNotFound, "Proposta não encontrada")
		return
	}
	_ = p.Vote(req.Address, req.Approve)
	p.CheckAndClose(h.snapshotStakes())
	_ = DaoStore.SaveToDisk("data/proposals.db")
	WriteJSON(w, p)
}

func (h *Handler) GetProposal(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["id"]
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		WriteError(w, http.StatusBadRequest, "ID inválido")
		return
	}
	p, err := DaoStore.Get(id)
	if err != nil {
		WriteError(w, http.StatusNotFound, "Proposta não encontrada")
		return
	}
	WriteJSON(w, p)
}

func (h *Handler) ListProposals(w http.ResponseWriter, r *http.Request) {
	WriteJSON(w, DaoStore.List())
}

func (h *Handler) snapshotStakes() map[string]uint64 {
	snapshot := make(map[string]uint64)
	for addr, entry := range h.StakingStore.Snapshot() {
		snapshot[addr] = entry.Amount
	}
	return snapshot
}