//go:build e2e && production

package production

import (
	"crypto/tls"
	"fmt"
	"io"
	"net/http"
	"path/filepath"
	"testing"
	"time"

	"github.com/DeBrosOfficial/network/e2e"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// TestHTTPS_CertificateValid tests that HTTPS works with a valid certificate
func TestHTTPS_CertificateValid(t *testing.T) {
	env, err := e2e.LoadTestEnv()
	require.NoError(t, err, "Failed to load test environment")

	deploymentName := fmt.Sprintf("https-test-%d", time.Now().Unix())
	tarballPath := filepath.Join("../../testdata/apps/react-app")

	deploymentID := e2e.CreateTestDeployment(t, env, deploymentName, tarballPath)
	defer func() {
		if !env.SkipCleanup {
			e2e.DeleteDeployment(t, env, deploymentID)
		}
	}()

	// Wait for deployment and certificate provisioning
	time.Sleep(5 * time.Second)

	domain := env.BuildDeploymentDomain(deploymentName)
	httpsURL := fmt.Sprintf("https://%s", domain)

	t.Run("HTTPS connection with certificate verification", func(t *testing.T) {
		// Create client that DOES verify certificates
		client := &http.Client{
			Timeout: 30 * time.Second,
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{
					// Do NOT skip verification - we want to test real certs
					InsecureSkipVerify: false,
				},
			},
		}

		req, err := http.NewRequest("GET", httpsURL+"/", nil)
		require.NoError(t, err)

		resp, err := client.Do(req)
		if err != nil {
			// Certificate might not be ready yet, or domain might not resolve
			t.Logf("⚠ HTTPS request failed (this may be expected if certs are still provisioning): %v", err)
			t.Skip("HTTPS not available or certificate not ready")
			return
		}
		defer resp.Body.Close()

		body, _ := io.ReadAll(resp.Body)
		if resp.StatusCode != http.StatusOK {
			t.Logf("HTTPS returned %d (deployment may not be routed yet): %s", resp.StatusCode, string(body))
		}

		// Check TLS connection state
		if resp.TLS != nil {
			t.Logf("✓ HTTPS works with valid certificate")
			t.Logf("   - Domain: %s", domain)
			t.Logf("   - TLS Version: %x", resp.TLS.Version)
			t.Logf("   - Cipher Suite: %x", resp.TLS.CipherSuite)
			if len(resp.TLS.PeerCertificates) > 0 {
				cert := resp.TLS.PeerCertificates[0]
				t.Logf("   - Certificate Subject: %s", cert.Subject)
				t.Logf("   - Certificate Issuer: %s", cert.Issuer)
				t.Logf("   - Valid Until: %s", cert.NotAfter)
			}
		}
	})
}

// TestHTTPS_CertificateDetails tests certificate properties
func TestHTTPS_CertificateDetails(t *testing.T) {
	env, err := e2e.LoadTestEnv()
	require.NoError(t, err, "Failed to load test environment")

	t.Run("Base domain certificate", func(t *testing.T) {
		httpsURL := fmt.Sprintf("https://%s", env.BaseDomain)

		// Connect and get certificate info
		conn, err := tls.Dial("tcp", env.BaseDomain+":443", &tls.Config{
			InsecureSkipVerify: true, // We just want to inspect the cert
		})
		if err != nil {
			t.Logf("⚠ Could not connect to %s:443: %v", env.BaseDomain, err)
			t.Skip("HTTPS not available on base domain")
			return
		}
		defer conn.Close()

		certs := conn.ConnectionState().PeerCertificates
		require.NotEmpty(t, certs, "Should have certificates")

		cert := certs[0]
		t.Logf("Certificate for %s:", env.BaseDomain)
		t.Logf("  - Subject: %s", cert.Subject)
		t.Logf("  - DNS Names: %v", cert.DNSNames)
		t.Logf("  - Valid From: %s", cert.NotBefore)
		t.Logf("  - Valid Until: %s", cert.NotAfter)
		t.Logf("  - Issuer: %s", cert.Issuer)

		// Check that certificate covers our domain
		coversDomain := false
		for _, name := range cert.DNSNames {
			if name == env.BaseDomain || name == "*."+env.BaseDomain {
				coversDomain = true
				break
			}
		}
		assert.True(t, coversDomain, "Certificate should cover %s", env.BaseDomain)

		// Check certificate is not expired
		assert.True(t, time.Now().Before(cert.NotAfter), "Certificate should not be expired")
		assert.True(t, time.Now().After(cert.NotBefore), "Certificate should be valid now")

		// Make actual HTTPS request to verify it works
		client := &http.Client{
			Timeout: 30 * time.Second,
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{
					InsecureSkipVerify: false,
				},
			},
		}

		resp, err := client.Get(httpsURL)
		if err != nil {
			t.Logf("⚠ HTTPS request failed: %v", err)
		} else {
			resp.Body.Close()
			t.Logf("✓ HTTPS request succeeded with status %d", resp.StatusCode)
		}
	})
}

// TestHTTPS_HTTPRedirect tests that HTTP requests are redirected to HTTPS
func TestHTTPS_HTTPRedirect(t *testing.T) {
	env, err := e2e.LoadTestEnv()
	require.NoError(t, err, "Failed to load test environment")

	t.Run("HTTP redirects to HTTPS", func(t *testing.T) {
		// Create client that doesn't follow redirects
		client := &http.Client{
			Timeout: 30 * time.Second,
			CheckRedirect: func(req *http.Request, via []*http.Request) error {
				return http.ErrUseLastResponse
			},
		}

		httpURL := fmt.Sprintf("http://%s", env.BaseDomain)

		resp, err := client.Get(httpURL)
		if err != nil {
			t.Logf("⚠ HTTP request failed: %v", err)
			t.Skip("HTTP not available or redirects not configured")
			return
		}
		defer resp.Body.Close()

		// Check for redirect
		if resp.StatusCode >= 300 && resp.StatusCode < 400 {
			location := resp.Header.Get("Location")
			t.Logf("✓ HTTP redirects to: %s (status %d)", location, resp.StatusCode)
			assert.Contains(t, location, "https://", "Should redirect to HTTPS")
		} else if resp.StatusCode == http.StatusOK {
			// HTTP might just serve content directly in some configurations
			t.Logf("⚠ HTTP returned 200 instead of redirect (HTTPS redirect may not be configured)")
		} else {
			t.Logf("HTTP returned status %d", resp.StatusCode)
		}
	})
}
