package feishu

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

	"github.com/stretchr/testify/require"
)

func TestEncodeDecodeAuthStateRoundTripAndValidation(t *testing.T) {
	t.Parallel()

	issuedAt := time.Date(2026, 5, 8, 1, 2, 3, 0, time.UTC)
	state, err := EncodeAuthState([]byte("secret"), " acme ", issuedAt)
	require.NoError(t, err)

	payload, err := DecodeAuthState([]byte("secret"), state, issuedAt.Add(time.Minute))
	require.NoError(t, err)
	require.Equal(t, "acme", payload.OrganizationSlug)
	require.Equal(t, issuedAt.Unix(), payload.IssuedAtUnix)

	_, err = DecodeAuthState([]byte("secret"), state+"x", issuedAt.Add(time.Minute))
	require.ErrorContains(t, err, "invalid feishu auth state")
	_, err = DecodeAuthState([]byte("secret"), state, issuedAt.Add(11*time.Minute))
	require.ErrorContains(t, err, "expired")
}

func TestBuildAuthorizeURLAndExchangeCode(t *testing.T) {
	t.Parallel()

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		switch r.URL.Path {
		case feishuAuthTokenPath:
			require.Equal(t, http.MethodPost, r.Method)
			var body map[string]string
			require.NoError(t, json.NewDecoder(r.Body).Decode(&body))
			require.Equal(t, "client-id", body["client_id"])
			require.Equal(t, "client-secret", body["client_secret"])
			require.Equal(t, "auth-code", body["code"])
			_ = json.NewEncoder(w).Encode(map[string]any{"code": 0, "access_token": "user-token"})
		case "/open-apis/authen/v1/user_info":
			require.Equal(t, "Bearer user-token", r.Header.Get("Authorization"))
			_ = json.NewEncoder(w).Encode(map[string]any{"code": 0, "data": map[string]any{"user_id": " user_1 ", "en_name": " Ada ", "email": " ada@example.com "}})
		default:
			http.NotFound(w, r)
		}
	}))
	defer server.Close()

	client, err := NewFeishuAuthHTTPClient(FeishuAuthHTTPClientOptions{BaseURL: server.URL, AppID: " client-id ", AppSecret: " client-secret ", HTTPClient: server.Client()})
	require.NoError(t, err)

	authorizeURL, err := client.BuildAuthorizeURL("https://agentteam/callback", "state")
	require.NoError(t, err)
	parsed, err := url.Parse(authorizeURL)
	require.NoError(t, err)
	require.Equal(t, feishuAuthAuthorizePath, parsed.Path)
	require.Equal(t, "client-id", parsed.Query().Get("client_id"))
	require.Equal(t, feishuAuthRequiredScopeUserID, parsed.Query().Get("scope"))

	identity, err := client.ExchangeCode(context.Background(), " auth-code ", "https://agentteam/callback")
	require.NoError(t, err)
	require.Equal(t, "user_1", identity.UserID)
	require.Equal(t, "Ada", identity.Name)
	require.Equal(t, "ada@example.com", identity.Email)
}

func TestFeishuAuthValidationHelpers(t *testing.T) {
	t.Parallel()

	_, err := NewFeishuAuthHTTPClient(FeishuAuthHTTPClientOptions{BaseURL: "ftp://example", AppID: "app", AppSecret: "secret"})
	require.ErrorContains(t, err, "must use http or https")
	_, err = normalizeFeishuRedirectURI("mailto:ada@example.com")
	require.ErrorContains(t, err, "is invalid")
	require.Equal(t, "https://accounts.feishu.cn", resolveFeishuAuthorizeBaseURL(&url.URL{Scheme: "https", Host: "open.feishu.cn"}))
	require.Contains(t, feishuAuthTokenErrorMessage(feishuAuthTokenResponse{Code: 1, Error_description: "bad code"}), "bad code")
}
