package auth

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"
)

const (
	CodexClientID    = "app_EMoamEEZ73f0CkXaXp7hrann"
	CodexRedirectURI = "http://localhost:1455/auth/callback"
	CodexScope       = "openid profile email offline_access"
)

// CodexTokens Codex Token 结构
type CodexTokens struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	IDToken      string `json:"id_token"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int    `json:"expires_in"`
	ExpiredAt    string `json:"expired_at,omitempty"`
}

// S2AAuthURLRequest S2A 授权 URL 请求
type S2AAuthURLRequest struct {
	ProxyID *int `json:"proxy_id,omitempty"`
}

// S2AAuthURLResponse S2A 授权 URL 响应
type S2AAuthURLResponse struct {
	Code int `json:"code"`
	Data struct {
		AuthURL   string `json:"auth_url"`
		SessionID string `json:"session_id"`
	} `json:"data"`
	Message string `json:"message,omitempty"`
}

// S2ACreateFromOAuthRequest 提交 OAuth 入库请求
type S2ACreateFromOAuthRequest struct {
	SessionID   string `json:"session_id"`
	Code        string `json:"code"`
	Name        string `json:"name,omitempty"`
	Concurrency int    `json:"concurrency,omitempty"`
	Priority    int    `json:"priority,omitempty"`
	GroupIDs    []int  `json:"group_ids,omitempty"`
	ProxyID     *int   `json:"proxy_id,omitempty"`
}

// S2ACreateFromOAuthResponse 入库响应
type S2ACreateFromOAuthResponse struct {
	Code int `json:"code"`
	Data struct {
		ID          int    `json:"id"`
		Name        string `json:"name"`
		Platform    string `json:"platform"`
		Type        string `json:"type"`
		Status      string `json:"status"`
		Concurrency int    `json:"concurrency"`
		Priority    int    `json:"priority"`
	} `json:"data"`
	Message string `json:"message,omitempty"`
}

// GenerateS2AAuthURL 从 S2A 生成 Codex 授权 URL
func GenerateS2AAuthURL(s2aAPIBase, s2aAdminKey string, proxyID *int) (*S2AAuthURLResponse, error) {
	client := &http.Client{Timeout: 15 * time.Second}

	apiURL := s2aAPIBase + "/api/v1/admin/openai/generate-auth-url"

	payload := S2AAuthURLRequest{ProxyID: proxyID}
	body, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", apiURL, bytes.NewReader(body))
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("X-Api-Key", s2aAdminKey)

	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("请求失败: %v", err)
	}
	defer resp.Body.Close()

	respBody, _ := io.ReadAll(resp.Body)

	if len(respBody) > 0 && respBody[0] == '<' {
		return nil, fmt.Errorf("服务器返回 HTML: %s", string(respBody)[:min(100, len(respBody))])
	}

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(respBody)[:min(200, len(respBody))])
	}

	var result S2AAuthURLResponse
	if err := json.Unmarshal(respBody, &result); err != nil {
		return nil, fmt.Errorf("解析响应失败: %v, body: %s", err, string(respBody)[:min(100, len(respBody))])
	}

	if result.Code != 0 {
		return nil, fmt.Errorf("S2A 错误: %s", result.Message)
	}

	return &result, nil
}

// SubmitS2AOAuth 提交 OAuth code 到 S2A 入库
func SubmitS2AOAuth(s2aAPIBase, s2aAdminKey, sessionID, code, name string, concurrency, priority int, groupIDs []int, proxyID *int) (*S2ACreateFromOAuthResponse, error) {
	client := &http.Client{Timeout: 30 * time.Second}

	apiURL := s2aAPIBase + "/api/v1/admin/openai/create-from-oauth"

	payload := S2ACreateFromOAuthRequest{
		SessionID:   sessionID,
		Code:        code,
		Name:        name,
		Concurrency: concurrency,
		Priority:    priority,
		GroupIDs:    groupIDs,
		ProxyID:     proxyID,
	}
	body, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", apiURL, bytes.NewReader(body))
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("X-Api-Key", s2aAdminKey)

	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("请求失败: %v", err)
	}
	defer resp.Body.Close()

	respBody, _ := io.ReadAll(resp.Body)

	var result S2ACreateFromOAuthResponse
	if err := json.Unmarshal(respBody, &result); err != nil {
		return nil, fmt.Errorf("解析响应失败: %v", err)
	}

	if result.Code != 0 {
		return nil, fmt.Errorf("S2A 入库失败: %s", result.Message)
	}

	return &result, nil
}

// VerifyS2AAccount 验证账号入库状态
func VerifyS2AAccount(s2aAPIBase, s2aAdminKey, email string) (bool, error) {
	client := &http.Client{Timeout: 30 * time.Second}

	apiURL := fmt.Sprintf("%s/api/v1/admin/accounts?page=1&page_size=20&search=%s&timezone=Asia/Shanghai", s2aAPIBase, url.QueryEscape(email))

	req, _ := http.NewRequest("GET", apiURL, nil)
	req.Header.Set("Accept", "application/json")
	req.Header.Set("X-Api-Key", s2aAdminKey)

	resp, err := client.Do(req)
	if err != nil {
		return false, fmt.Errorf("请求失败: %v", err)
	}
	defer resp.Body.Close()

	respBody, _ := io.ReadAll(resp.Body)

	var result struct {
		Code int `json:"code"`
		Data struct {
			Items []struct {
				ID     int    `json:"id"`
				Name   string `json:"name"`
				Status string `json:"status"`
			} `json:"items"`
			Total int `json:"total"`
		} `json:"data"`
	}

	if err := json.Unmarshal(respBody, &result); err != nil {
		return false, fmt.Errorf("解析响应失败: %v", err)
	}

	if result.Code != 0 || result.Data.Total == 0 {
		return false, nil
	}

	for _, item := range result.Data.Items {
		if item.Status == "active" {
			return true, nil
		}
	}

	return false, nil
}

// ExtractCodeFromCallbackURL 从回调 URL 中提取 code
func ExtractCodeFromCallbackURL(callbackURL string) string {
	parsedURL, err := url.Parse(callbackURL)
	if err != nil {
		return ""
	}
	return parsedURL.Query().Get("code")
}

// RefreshCodexToken 刷新 Codex token
func RefreshCodexToken(refreshToken string, proxyURL string) (*CodexTokens, error) {
	client := &http.Client{Timeout: 30 * time.Second}

	if proxyURL != "" {
		proxyURLParsed, _ := url.Parse(proxyURL)
		client.Transport = &http.Transport{Proxy: http.ProxyURL(proxyURLParsed)}
	}

	data := url.Values{
		"client_id":     {CodexClientID},
		"grant_type":    {"refresh_token"},
		"refresh_token": {refreshToken},
		"scope":         {"openid profile email"},
	}

	req, _ := http.NewRequest("POST", "https://auth.openai.com/oauth/token", strings.NewReader(data.Encode()))
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("刷新 token 失败: %d, %s", resp.StatusCode, string(body)[:min(200, len(body))])
	}

	var tokens CodexTokens
	if err := json.Unmarshal(body, &tokens); err != nil {
		return nil, err
	}

	if tokens.ExpiresIn > 0 {
		expiredAt := time.Now().Add(time.Duration(tokens.ExpiresIn) * time.Second)
		tokens.ExpiredAt = expiredAt.Format(time.RFC3339)
	}

	return &tokens, nil
}

// ExtractWorkspaceFromCookie 从 cookie 提取 workspace_id
func ExtractWorkspaceFromCookie(cookieValue string) string {
	parts := strings.Split(cookieValue, ".")
	if len(parts) < 1 {
		return ""
	}

	payload := parts[0]
	if m := len(payload) % 4; m != 0 {
		payload += strings.Repeat("=", 4-m)
	}

	decoded, err := base64.StdEncoding.DecodeString(payload)
	if err != nil {
		decoded, err = base64.RawURLEncoding.DecodeString(parts[0])
		if err != nil {
			return ""
		}
	}

	var data struct {
		Workspaces []struct {
			ID string `json:"id"`
		} `json:"workspaces"`
	}

	if err := json.Unmarshal(decoded, &data); err != nil {
		return ""
	}

	if len(data.Workspaces) > 0 {
		return data.Workspaces[0].ID
	}

	return ""
}
