package auth

import (
	"context"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/core/authidentity"
	"github.com/tidbcloud/AgentTeam/internal/service/authflow"
	"github.com/tidbcloud/AgentTeam/internal/store/identity"
)

// Store is the identity/session storage port used by auth and identity routes.
type Store interface {
	AuthenticateSession(ctx context.Context, token string) (identity.AuthenticatedUser, error)
	BootstrapInitialAdmin(ctx context.Context, email string, name string, displayName string, passwordHash string, tokenHash string, expiresAt time.Time) (identity.AuthenticatedUser, error)
	CompleteMobileVerificationAttempt(ctx context.Context, attemptID string, params identity.CompleteMobileVerificationAttemptParams) error
	CreateMobileVerificationAttempt(ctx context.Context, userID string, mobile string, expiresAt time.Time) (identity.MobileVerificationAttempt, error)
	CreateMobileVerificationToken(ctx context.Context, userID string, mobile string, tokenHash string, expiresAt time.Time) error
	CreatePasswordResetToken(ctx context.Context, userID string, tokenHash string, expiresAt time.Time) error
	CreateRefreshToken(ctx context.Context, userID string, tokenHash string, expiresAt time.Time) error
	CreateSessionAndRefreshToken(ctx context.Context, userID string, sessionTokenHash string, sessionExpiresAt time.Time, refreshTokenHash string, refreshExpiresAt time.Time) (identity.UserSession, error)
	CreateVerificationToken(ctx context.Context, userID string, tokenHash string, expiresAt time.Time) error
	CreateVerifiedUser(ctx context.Context, email string, name string, displayName string, passwordHash string) (identity.User, error)
	DeleteMobileVerificationToken(ctx context.Context, userID string, tokenHash string) error
	DeleteUserByID(ctx context.Context, userID string) error
	ExchangeMiniappPairingCodeForSession(ctx context.Context, code string, client authidentity.MiniappPairingClient, sessionTTL time.Duration) (identity.MiniappPairingExchangeResult, error)
	FindOrCreateUserByPingCAPAuth(ctx context.Context, userInfo identity.PingCAPAuthUserInfo) (identity.User, bool, error)
	FindUserByEmail(ctx context.Context, email string) (identity.User, error)
	FindUserByLoginIdentifier(ctx context.Context, identifier string) (identity.User, error)
	GetActiveMobileVerificationCodeForUser(ctx context.Context, userID string) (identity.ActiveMobileVerificationCode, bool, error)
	ListMobileVerificationAttemptsForUser(ctx context.Context, userID string, limit int) ([]identity.MobileVerificationAttempt, error)
	ListActiveMobileSessions(ctx context.Context, userID string) ([]identity.MobileSession, error)
	LoadUserPasswordHash(ctx context.Context, userID string) (string, error)
	MarkUserEmailVerified(ctx context.Context, userID string) (identity.User, error)
	RegisterUser(ctx context.Context, email string, name string, displayName string, passwordHash string, verificationTokenHash string, verificationExpiresAt time.Time) (identity.User, error)
	ResetPasswordWithToken(ctx context.Context, token string, nextPasswordHash string) error
	RevokeRefreshToken(ctx context.Context, refreshToken string) error
	RevokeSession(ctx context.Context, sessionID string) error
	RevokeMobileSession(ctx context.Context, userID string, sessionFamilyID string) error
	RotateRefreshTokenAndCreateSession(ctx context.Context, refreshToken string, nextTokenHash string, nextExpiresAt time.Time, sessionTokenHash string, sessionExpiresAt time.Time) (string, identity.UserSession, error)
	SystemInitialized(ctx context.Context) (bool, error)
	UpdateUserAvatarURL(ctx context.Context, userID string, avatarURL string) (identity.User, error)
	UpdateUserDisplayName(ctx context.Context, userID string, displayName string) (identity.User, error)
	UpdateUserPasswordHash(ctx context.Context, userID string, passwordHash string) (identity.User, error)
	VerifyEmailToken(ctx context.Context, token string) (identity.User, error)
	VerifyMobileToken(ctx context.Context, userID string, token string) (identity.User, error)
}

// MobileSessionStore is the narrow account-scoped port used by mobile login management.
type MobileSessionStore interface {
	ListActiveMobileSessions(ctx context.Context, userID string) ([]identity.MobileSession, error)
	RevokeMobileSession(ctx context.Context, userID string, sessionFamilyID string) error
}

// AuthFlow is the narrow cross-domain service port used by auth routes.
type AuthFlow interface {
	RegistrationAllowedForEmail(ctx context.Context, email string, staticallyAllowed bool) (bool, error)
	EnsureDefaultWorkspace(ctx context.Context, user identity.User, options authflow.DefaultWorkspaceOptions) error
	FindInviteInfoByToken(ctx context.Context, token string) (authflow.InviteInfo, bool, error)
	FindWorkspaceInviteInfoByID(ctx context.Context, inviteID string) (authflow.InviteInfo, bool, error)
	AcceptInviteByToken(ctx context.Context, user identity.User, token string) (authflow.InviteAcceptance, bool, error)
	ListPendingInvitesForUser(ctx context.Context, user identity.User) ([]authflow.PendingInvite, error)
	AcceptPendingInviteByID(ctx context.Context, user identity.User, inviteID string) (authflow.InviteAcceptance, bool, error)
	DismissPendingInviteByID(ctx context.Context, user identity.User, inviteID string) (bool, error)
	AutoJoinOrganizationsAfterVerifiedLogin(ctx context.Context, user identity.User, loginIdentifierKind authidentity.Kind) error
}

// Realtime emits auth-driven workspace cache invalidation events and keeps
// existing streaming connections in sync when invite acceptance auto-joins
// the workspace's all-channel.
type Realtime interface {
	EmitChannelMembersUpdated(workspaceID string, channelID string)
	EmitWorkspaceMembersUpdated(workspaceID string)
	SubscribeScopeForUser(workspaceID string, userID string, scopeID string)
}

// OrganizationProvider is the organization auth subset needed by Feishu routes.
type OrganizationProvider interface {
	AuthenticateFeishuLogin(ctx context.Context, code string, state string, redirectURI string) (identity.User, error)
	BuildFeishuLoginURL(ctx context.Context, organizationSlug string, redirectURI string) (string, error)
}

const (
	MobileVerificationAttemptStatusFailed = identity.MobileVerificationAttemptStatusFailed
	MobileVerificationAttemptStatusSent   = identity.MobileVerificationAttemptStatusSent
)

var ErrNotFound = api.ErrNotFound

var _ AuthFlow = (*authflow.Service)(nil)
