package handlers

import (
	"errors"
	"net/url"
	"strings"
)

// LoginRequest POST /api/auth/login JSON body
type LoginRequest struct {
	Account        string `json:"account"`
	Password       string `json:"password"`
	ClientID       string `json:"clientId"`
	ClientName     string `json:"clientName"`
	TurnstileToken string `json:"turnstileToken"`
}

// VerifyRequest POST /api/auth/verify
type VerifyRequest struct {
	Token string `json:"token"`
}

// RegisterRequest POST /api/auth/register
type RegisterRequest struct {
	Account        string `json:"account"`
	Password       string `json:"password"`
	Username       string `json:"username"`
	Email          string `json:"email"`
	InviteCode     string `json:"inviteCode"`
	TurnstileToken string `json:"turnstileToken"`
}

// VerifyEmailRequest POST /api/auth/verify-email
type VerifyEmailRequest struct {
	Account string `json:"account"`
	Code    string `json:"code"`
}

// UpdateProfileRequest PUT /api/auth/profile
type UpdateProfileRequest struct {
	Password   *string `json:"password"`
	Username   *string `json:"username"`
	Phone      *string `json:"phone"`
	AvatarURL  *string `json:"avatarUrl"`
	WebsiteURL *string `json:"websiteUrl"`
	Bio        *string `json:"bio"`
}

// ForgotPasswordRequest POST /api/auth/forgot-password
type ForgotPasswordRequest struct {
	Account string `json:"account"`
	Email   string `json:"email"`
}

// ResetPasswordRequest POST /api/auth/reset-password
type ResetPasswordRequest struct {
	Account     string `json:"account"`
	Code        string `json:"code"`
	NewPassword string `json:"newPassword"`
}

// SecondaryEmailRequest POST /api/auth/secondary-email/request
type SecondaryEmailRequest struct {
	Email string `json:"email"`
}

// VerifySecondaryEmailRequest POST /api/auth/secondary-email/verify
type VerifySecondaryEmailRequest struct {
	Email string `json:"email"`
	Code  string `json:"code"`
}

// UpdateCheckInConfigRequest PUT /api/admin/check-in/config
type UpdateCheckInConfigRequest struct {
	RewardCoins int `json:"rewardCoins"`
}

// UpdateRegistrationPolicyRequest PUT /api/admin/registration
type UpdateRegistrationPolicyRequest struct {
	RequireInviteCode         bool   `json:"requireInviteCode"`
	ForbiddenAccounts         string `json:"forbiddenAccounts"`
	InviteRegisterRewardCoins *int   `json:"inviteRegisterRewardCoins"` // nil 表示不修改此项
}

// CreateInviteRequest POST /api/admin/registration/invites
type CreateInviteRequest struct {
	Note      string `json:"note"`
	MaxUses   int    `json:"maxUses"`
	ExpiresAt string `json:"expiresAt"`
}

// CreateUserRequest POST /api/admin/users
type CreateUserRequest struct {
	Account         string   `json:"account"`
	Password        string   `json:"password"`
	Username        string   `json:"username"`
	Email           string   `json:"email"`
	Level           int      `json:"level"`
	SproutCoins     int      `json:"sproutCoins"`
	SecondaryEmails []string `json:"secondaryEmails"`
	Phone           string   `json:"phone"`
	AvatarURL       string   `json:"avatarUrl"`
	WebsiteURL      string   `json:"websiteUrl"`
	Bio             string   `json:"bio"`
}

const maxBanReasonLen = 500

// UpdateUserRequest PUT /api/admin/users/:account
type UpdateUserRequest struct {
	Password        *string   `json:"password"`
	Username        *string   `json:"username"`
	Email           *string   `json:"email"`
	Level           *int      `json:"level"`
	SproutCoins     *int      `json:"sproutCoins"`
	SecondaryEmails *[]string `json:"secondaryEmails"`
	Phone           *string   `json:"phone"`
	AvatarURL       *string   `json:"avatarUrl"`
	WebsiteURL      *string   `json:"websiteUrl"`
	Bio             *string   `json:"bio"`
	Banned          *bool     `json:"banned"`
	BanReason       *string   `json:"banReason"`
}

// OAuthBindURLRequest POST /api/auth/oauth/:provider/bind
type OAuthBindURLRequest struct {
	ReturnTo string `json:"returnTo"`
}

// PutAdminOAuthRequest PUT /api/admin/oauth
type PutAdminOAuthRequest struct {
	GitHubEnabled                      bool     `json:"githubEnabled"`
	GiteaEnabled                       bool     `json:"giteaEnabled"`
	GoogleEnabled                      bool     `json:"googleEnabled"`
	MicrosoftEnabled                   bool     `json:"microsoftEnabled"`
	LinuxdoEnabled                     bool     `json:"linuxdoEnabled"`
	GitHubClientID                     string   `json:"githubClientId"`
	GitHubClientSecret                 string   `json:"githubClientSecret"`
	GiteaBaseURL                       string   `json:"giteaBaseUrl"`
	GiteaClientID                      string   `json:"giteaClientId"`
	GiteaClientSecret                  string   `json:"giteaClientSecret"`
	GoogleClientID                     string   `json:"googleClientId"`
	GoogleClientSecret                 string   `json:"googleClientSecret"`
	MicrosoftClientID                  string   `json:"microsoftClientId"`
	MicrosoftClientSecret              string   `json:"microsoftClientSecret"`
	MicrosoftTenant                    string   `json:"microsoftTenant"`
	LinuxdoConnectBaseURL              string   `json:"linuxdoConnectBaseUrl"`
	LinuxdoClientID                    string   `json:"linuxdoClientId"`
	LinuxdoClientSecret                string   `json:"linuxdoClientSecret"`
	GitHubLogoURL                      string   `json:"githubLogoUrl"`
	GiteaLogoURL                       string   `json:"giteaLogoUrl"`
	GoogleLogoURL                      string   `json:"googleLogoUrl"`
	MicrosoftLogoURL                   string   `json:"microsoftLogoUrl"`
	LinuxdoLogoURL                     string   `json:"linuxdoLogoUrl"`
	AllowedReturnPrefixes              []string `json:"allowedReturnPrefixes"`
	AllowOAuthSignUpWhenInviteRequired bool     `json:"allowOAuthSignUpWhenInviteRequired"`
}

// PutAdminTurnstileRequest PUT /api/admin/turnstile
type PutAdminTurnstileRequest struct {
	Enabled   bool   `json:"enabled"`
	SiteKey   string `json:"siteKey"`
	SecretKey string `json:"secretKey"`
}

const maxWebsiteURLLen = 2048

func normalizePublicWebsiteURL(raw string) (string, error) {
	s := strings.TrimSpace(raw)
	if s == "" {
		return "", nil
	}
	if len(s) > maxWebsiteURLLen {
		return "", errors.New("website url is too long")
	}
	lower := strings.ToLower(s)
	if strings.HasPrefix(lower, "javascript:") || strings.HasPrefix(lower, "data:") {
		return "", errors.New("invalid website url")
	}
	candidate := s
	if !strings.Contains(candidate, "://") {
		candidate = "https://" + candidate
	}
	u, err := url.Parse(candidate)
	if err != nil || u.Host == "" {
		return "", errors.New("invalid website url")
	}
	scheme := strings.ToLower(u.Scheme)
	if scheme != "http" && scheme != "https" {
		return "", errors.New("only http and https urls are allowed")
	}
	u.Scheme = scheme
	return u.String(), nil
}
