package handlers

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/go-chi/chi/v5"

	"github.com/orchard9/rdev/internal/domain"
)

// mockDiagnosticsGetter implements DiagnosticsGetter for testing.
type mockDiagnosticsGetter struct {
	diagnostics *domain.ProjectDiagnostics
	err         error
}

func (m *mockDiagnosticsGetter) GetDiagnostics(_ context.Context, projectID string) (*domain.ProjectDiagnostics, error) {
	if m.err != nil {
		return nil, m.err
	}
	if m.diagnostics != nil {
		return m.diagnostics, nil
	}
	// Return default healthy diagnostics
	return &domain.ProjectDiagnostics{
		ProjectID:   projectID,
		GeneratedAt: time.Now().UTC(),
		Summary:     domain.DiagnosticsSummaryHealthy,
		Issues:      []domain.DiagnosticIssue{},
	}, nil
}

func TestDiagnosticsHandler_GetDiagnostics_Success(t *testing.T) {
	getter := &mockDiagnosticsGetter{}
	projects := newMockProjectRepo()
	h := NewDiagnosticsHandler(getter, projects)

	// Create router with chi to handle URL params
	r := chi.NewRouter()
	r.Use(testAdminAuth) // Add auth context for tests
	h.Mount(r)

	req := httptest.NewRequest("GET", "/projects/test-project/diagnostics/", nil)
	rec := httptest.NewRecorder()

	r.ServeHTTP(rec, req)

	if rec.Code != http.StatusOK {
		t.Errorf("GetDiagnostics() status = %d, want %d; body = %s", rec.Code, http.StatusOK, rec.Body.String())
	}

	var resp map[string]any
	if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil {
		t.Fatalf("failed to decode response: %v", err)
	}

	data, ok := resp["data"].(map[string]any)
	if !ok {
		t.Fatalf("response missing data field")
	}

	if data["project_id"] != "test-project" {
		t.Errorf("project_id = %q, want %q", data["project_id"], "test-project")
	}
	if data["summary"] != domain.DiagnosticsSummaryHealthy {
		t.Errorf("summary = %q, want %q", data["summary"], domain.DiagnosticsSummaryHealthy)
	}
}

func TestDiagnosticsHandler_GetDiagnostics_WithIssues(t *testing.T) {
	getter := &mockDiagnosticsGetter{
		diagnostics: &domain.ProjectDiagnostics{
			ProjectID:   "unhealthy-project",
			GeneratedAt: time.Now().UTC(),
			Summary:     domain.DiagnosticsSummaryUnhealthy,
			Issues: []domain.DiagnosticIssue{
				{
					Severity: domain.DiagnosticSeverityError,
					Source:   domain.DiagnosticSourceCI,
					Message:  "CI build #42 failed",
				},
				{
					Severity: domain.DiagnosticSeverityWarning,
					Source:   domain.DiagnosticSourceRegistry,
					Message:  "Container registry slow",
				},
			},
		},
	}
	projects := newMockProjectRepo()
	h := NewDiagnosticsHandler(getter, projects)

	r := chi.NewRouter()
	r.Use(testAdminAuth) // Add auth context for tests
	h.Mount(r)

	req := httptest.NewRequest("GET", "/projects/unhealthy-project/diagnostics/", nil)
	rec := httptest.NewRecorder()

	r.ServeHTTP(rec, req)

	if rec.Code != http.StatusOK {
		t.Errorf("GetDiagnostics() status = %d, want %d", rec.Code, http.StatusOK)
	}

	var resp map[string]any
	if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil {
		t.Fatalf("failed to decode response: %v", err)
	}

	data, ok := resp["data"].(map[string]any)
	if !ok {
		t.Fatalf("response missing data field")
	}

	if data["summary"] != domain.DiagnosticsSummaryUnhealthy {
		t.Errorf("summary = %q, want %q", data["summary"], domain.DiagnosticsSummaryUnhealthy)
	}

	issues, ok := data["issues"].([]any)
	if !ok {
		t.Fatalf("response missing issues field")
	}
	if len(issues) != 2 {
		t.Errorf("issues count = %d, want %d", len(issues), 2)
	}
}

func TestDiagnosticsHandler_GetDiagnostics_MissingProjectID(t *testing.T) {
	getter := &mockDiagnosticsGetter{}
	projects := newMockProjectRepo()
	h := NewDiagnosticsHandler(getter, projects)

	// Direct call without chi router to test missing projectId
	req := httptest.NewRequest("GET", "/projects//diagnostics/", nil)
	rec := httptest.NewRecorder()

	h.GetDiagnostics(rec, req)

	if rec.Code != http.StatusBadRequest {
		t.Errorf("GetDiagnostics() status = %d, want %d", rec.Code, http.StatusBadRequest)
	}
}
