//go:build e2e
// +build e2e

package e2e

import (
	"bytes"
	"encoding/json"
	"io"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"

	"github.com/rede5/gohorsejobs/backend/internal/database"
	"github.com/rede5/gohorsejobs/backend/internal/router"
)

var testServer *httptest.Server

// TestMain sets up the test environment for all E2E tests
func TestMain(m *testing.M) {
	// Set environment variables for testing
	setTestEnv()

	// Initialize database connection
	database.InitDB()

	// Create test server
	testServer = httptest.NewServer(router.NewRouter())
	defer testServer.Close()

	// Run tests
	code := m.Run()

	// Cleanup
	cleanupTestData()

	os.Exit(code)
}

// setTestEnv sets up environment variables for testing
// Uses the same database as development (loaded from .env in CI/CD or manually set)
func setTestEnv() {
	// Only set if not already set (allows override via .env file)
	// These are defaults for when running tests without sourcing .env
	if os.Getenv("DB_HOST") == "" {
		os.Setenv("DB_HOST", "db-60059.dc-sp-1.absamcloud.com")
	}
	if os.Getenv("DB_USER") == "" {
		os.Setenv("DB_USER", "yuki")
	}
	if os.Getenv("DB_PASSWORD") == "" {
		os.Setenv("DB_PASSWORD", "xl1zfmr6e9bb")
	}
	if os.Getenv("DB_NAME") == "" {
		os.Setenv("DB_NAME", "gohorsejobs_dev")
	}
	if os.Getenv("DB_PORT") == "" {
		os.Setenv("DB_PORT", "26868")
	}
	if os.Getenv("DB_SSLMODE") == "" {
		os.Setenv("DB_SSLMODE", "require")
	}
	if os.Getenv("JWT_SECRET") == "" {
		os.Setenv("JWT_SECRET", "gohorse-super-secret-key-2024-production")
	}
}

// cleanupTestData removes test data from the database
func cleanupTestData() {
	if database.DB != nil {
		// Clean up in reverse order of dependencies
		database.DB.Exec("DELETE FROM applications WHERE id > 0")
		database.DB.Exec("DELETE FROM jobs WHERE title LIKE 'E2E Test%'")
		database.DB.Exec("DELETE FROM companies WHERE name LIKE 'E2E Test%'")
	}
}

// httpClient helper for making requests to test server
type testClient struct {
	baseURL string
	token   string
}

func newTestClient() *testClient {
	return &testClient{
		baseURL: testServer.URL,
	}
}

func (c *testClient) setAuthToken(token string) {
	c.token = token
}

func (c *testClient) doRequest(method, path string, body interface{}) (*http.Response, error) {
	var reqBody io.Reader
	if body != nil {
		jsonData, err := json.Marshal(body)
		if err != nil {
			return nil, err
		}
		reqBody = bytes.NewReader(jsonData)
	}

	req, err := http.NewRequest(method, c.baseURL+path, reqBody)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")
	if c.token != "" {
		req.Header.Set("Authorization", "Bearer "+c.token)
	}

	return http.DefaultClient.Do(req)
}

func (c *testClient) get(path string) (*http.Response, error) {
	return c.doRequest("GET", path, nil)
}

func (c *testClient) post(path string, body interface{}) (*http.Response, error) {
	return c.doRequest("POST", path, body)
}

func (c *testClient) put(path string, body interface{}) (*http.Response, error) {
	return c.doRequest("PUT", path, body)
}

func (c *testClient) delete(path string) (*http.Response, error) {
	return c.doRequest("DELETE", path, nil)
}

// parseJSON helper to decode JSON response
func parseJSON(resp *http.Response, target interface{}) error {
	defer resp.Body.Close()
	return json.NewDecoder(resp.Body).Decode(target)
}

// TestHealthCheck verifies the server is running
func TestHealthCheck(t *testing.T) {
	client := newTestClient()

	resp, err := client.get("/health")
	if err != nil {
		t.Fatalf("Failed to make request: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		t.Errorf("Expected status 200, got %d", resp.StatusCode)
	}
}

// TestRootEndpoint verifies the API info endpoint
func TestRootEndpoint(t *testing.T) {
	client := newTestClient()

	resp, err := client.get("/")
	if err != nil {
		t.Fatalf("Failed to make request: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		t.Errorf("Expected status 200, got %d", resp.StatusCode)
	}

	var result map[string]interface{}
	if err := parseJSON(resp, &result); err != nil {
		t.Fatalf("Failed to parse JSON: %v", err)
	}

	if result["message"] != "🐴 GoHorseJobs API is running!" {
		t.Errorf("Unexpected message: %v", result["message"])
	}
}
