package message

import (
	"database/sql"
	"encoding/json"
	"net/http"

	"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/middleware"
	"github.com/go-chi/chi/v5"
)

type FeatureRequestHandler struct {
	db *sql.DB
}

func NewFeatureRequestHandler(db *sql.DB) *FeatureRequestHandler {
	return &FeatureRequestHandler{db: db}
}

func (h *FeatureRequestHandler) RegisterRoutes(r chi.Router) {
	r.Get("/", h.List)
	r.Post("/", h.Create)
	r.Post("/{id}/vote", h.Vote)
	r.Delete("/{id}/vote", h.Unvote)
	r.Patch("/{id}/status", h.UpdateStatus)
}

type featureRequestResponse struct {
	ID          string   `json:"id"`
	ServerID    string   `json:"server_id"`
	ChannelID   string   `json:"channel_id"`
	AuthorID    string   `json:"author_id"`
	Title       string   `json:"title"`
	Description string   `json:"description"`
	Status      string   `json:"status"`
	VoteCount   int      `json:"vote_count"`
	Voters      []string `json:"voters"`
	CreatedAt   string   `json:"created_at"`
	UpdatedAt   string   `json:"updated_at"`
}

func (h *FeatureRequestHandler) List(w http.ResponseWriter, r *http.Request) {
	serverID := chi.URLParam(r, "serverID")
	if serverID == "" {
		http.Error(w, `{"error":"serverID required"}`, http.StatusBadRequest)
		return
	}

	rows, err := h.db.QueryContext(r.Context(), `
		SELECT fr.id, fr.server_id, fr.channel_id, fr.author_id, fr.title, fr.description, fr.status,
		       fr.created_at, fr.updated_at,
		       COALESCE((SELECT count(*) FROM feature_request_votes frv WHERE frv.feature_request_id = fr.id), 0) as vote_count
		FROM feature_requests fr
		WHERE fr.server_id = $1
		ORDER BY vote_count DESC, fr.created_at DESC
	`, serverID)
	if err != nil {
		http.Error(w, `{"error":"query failed"}`, http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	var results []featureRequestResponse
	for rows.Next() {
		var fr featureRequestResponse
		if err := rows.Scan(&fr.ID, &fr.ServerID, &fr.ChannelID, &fr.AuthorID, &fr.Title, &fr.Description, &fr.Status, &fr.CreatedAt, &fr.UpdatedAt, &fr.VoteCount); err != nil {
			continue
		}
		// Fetch voters
		voterRows, _ := h.db.QueryContext(r.Context(), `
			SELECT user_id FROM feature_request_votes WHERE feature_request_id = $1
		`, fr.ID)
		if voterRows != nil {
			for voterRows.Next() {
				var vid string
				if voterRows.Scan(&vid) == nil {
					fr.Voters = append(fr.Voters, vid)
				}
			}
			voterRows.Close()
		}
		if fr.Voters == nil {
			fr.Voters = []string{}
		}
		results = append(results, fr)
	}
	if results == nil {
		results = []featureRequestResponse{}
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(results)
}

type createFeatureRequest struct {
	Title       string `json:"title"`
	Description string `json:"description"`
	ChannelID   string `json:"channel_id"`
}

func (h *FeatureRequestHandler) Create(w http.ResponseWriter, r *http.Request) {
	userID, ok := middleware.UserIDFromContext(r.Context())
	if !ok {
		http.Error(w, `{"error":"unauthorized"}`, http.StatusUnauthorized)
		return
	}

	serverID := chi.URLParam(r, "serverID")
	if serverID == "" {
		http.Error(w, `{"error":"serverID required"}`, http.StatusBadRequest)
		return
	}

	var req createFeatureRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
		return
	}

	if req.Title == "" {
		http.Error(w, `{"error":"title required"}`, http.StatusBadRequest)
		return
	}

	if req.ChannelID == "" {
		// Default to the first text channel in the server
		h.db.QueryRowContext(r.Context(), `
			SELECT id FROM channels WHERE server_id = $1 AND type = 'text' ORDER BY position LIMIT 1
		`, serverID).Scan(&req.ChannelID)
	}

	var fr featureRequestResponse
	err := h.db.QueryRowContext(r.Context(), `
		INSERT INTO feature_requests (server_id, channel_id, author_id, title, description)
		VALUES ($1, $2, $3, $4, $5)
		RETURNING id, server_id, channel_id, author_id, title, description, status, created_at, updated_at
	`, serverID, req.ChannelID, userID, req.Title, req.Description).Scan(
		&fr.ID, &fr.ServerID, &fr.ChannelID, &fr.AuthorID, &fr.Title, &fr.Description, &fr.Status, &fr.CreatedAt, &fr.UpdatedAt,
	)
	if err != nil {
		http.Error(w, `{"error":"failed to create feature request"}`, http.StatusInternalServerError)
		return
	}

	fr.VoteCount = 0
	fr.Voters = []string{}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(fr)
}

func (h *FeatureRequestHandler) Vote(w http.ResponseWriter, r *http.Request) {
	userID, ok := middleware.UserIDFromContext(r.Context())
	if !ok {
		http.Error(w, `{"error":"unauthorized"}`, http.StatusUnauthorized)
		return
	}

	id := chi.URLParam(r, "id")
	_, err := h.db.ExecContext(r.Context(), `
		INSERT INTO feature_request_votes (feature_request_id, user_id) VALUES ($1, $2) ON CONFLICT DO NOTHING
	`, id, userID)
	if err != nil {
		http.Error(w, `{"error":"vote failed"}`, http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.Write([]byte(`{"ok":true}`))
}

func (h *FeatureRequestHandler) Unvote(w http.ResponseWriter, r *http.Request) {
	userID, ok := middleware.UserIDFromContext(r.Context())
	if !ok {
		http.Error(w, `{"error":"unauthorized"}`, http.StatusUnauthorized)
		return
	}

	id := chi.URLParam(r, "id")
	h.db.ExecContext(r.Context(), `
		DELETE FROM feature_request_votes WHERE feature_request_id = $1 AND user_id = $2
	`, id, userID)

	w.WriteHeader(http.StatusOK)
	w.Write([]byte(`{"ok":true}`))
}

func (h *FeatureRequestHandler) UpdateStatus(w http.ResponseWriter, r *http.Request) {
	id := chi.URLParam(r, "id")

	var req struct {
		Status string `json:"status"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
		return
	}

	validStatuses := map[string]bool{"open": true, "planned": true, "done": true, "rejected": true}
	if !validStatuses[req.Status] {
		http.Error(w, `{"error":"invalid status"}`, http.StatusBadRequest)
		return
	}

	_, err := h.db.ExecContext(r.Context(), `
		UPDATE feature_requests SET status = $1, updated_at = NOW() WHERE id = $2
	`, req.Status, id)
	if err != nil {
		http.Error(w, `{"error":"update failed"}`, http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.Write([]byte(`{"ok":true}`))
}
