package main

import (
	"bytes"
	"net/http"
	"strconv"
	"testing"
	"time"
)

func TestReadIssueHandler(t *testing.T) {
	app := newTestApplication(t)
	ts := newTestServer(t, app, routes(app))
	defer ts.Close()

	token := ts.registerAndLogin(t, uniqueEmail(), "pa$$word123")

	req := map[string]any{
		"title":       "An old silent pond...",
		"description": "A frog jumps into the pond",
		"start_time":  time.Now().Format(time.RFC3339),
		"end_time":    time.Now().Add(24 * time.Hour).Format(time.RFC3339),
		"options":     []string{"Option A", "Option B", "Option C"},
	}

	code, _, res := ts.postJSONWithToken(t, "/v1/issues", token, req)
	if code != http.StatusCreated {
		t.Fatalf("seed issue: want 201 got %d: %s", code, res)
	}

	var createResp struct {
		Issue struct {
			ID int64 `json:"id"`
		} `json:"issue"`
	}
	mustUnmarshal(t, res, &createResp)
	issueID := createResp.Issue.ID

	tests := []struct {
		name     string
		urlPath  string
		wantCode int
		wantBody []byte
	}{
		{"Valid ID",        "/v1/issues/" + strconv.Itoa(int(issueID)), http.StatusOK, []byte("An old silent pond...")},
		{"Non-existent ID", "/v1/issues/" + strconv.Itoa(int(issueID+1)), http.StatusNotFound, nil},
		{"Negative ID",     "/v1/issues/-1", http.StatusNotFound, nil},
		{"Decimal ID",      "/v1/issues/1.23", http.StatusNotFound, nil},
		{"String ID",       "/v1/issues/foo", http.StatusNotFound, nil},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			code, _, body := ts.getWithToken(t, tt.urlPath, token)

			if code != tt.wantCode {
				t.Errorf("want %d; got %d", tt.wantCode, code)
			}

			if !bytes.Contains(body, tt.wantBody) {
				t.Errorf("want body to contain %q; got %q", tt.wantBody, string(body))
			}
		})
	}

	// verify options are present on a successful read
	code, _, body := ts.getWithToken(t, "/v1/issues/" + i64str(issueID), token)
	if code != http.StatusOK {
		t.Fatalf("read issue: want 200 got %d: %s", code, body)
	}

	var readResp struct {
		Options []struct {
			ID        int64  `json:"id"`
			Label     string `json:"label"`
			VoteCount int64  `json:"vote_count"`
		} `json:"options"`
	}
	mustUnmarshal(t, body, &readResp)

	if len(readResp.Options) != 3 {
		t.Fatalf("want 3 options, got %d: %s", len(readResp.Options), body)
	}

	for _, o := range readResp.Options {
		if o.VoteCount != 0 {
			t.Errorf("option %q: want vote_count 0, got %d", o.Label, o.VoteCount)
		}
	}

	labels := map[string]bool{}
	for _, o := range readResp.Options {
		labels[o.Label] = true
	}
	for _, want := range []string{"Option A", "Option B", "Option C"} {
		if !labels[want] {
			t.Errorf("missing option %q in response", want)
		}
	}
}
