package identity

import (
	"context"
	"fmt"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/model"
	"github.com/tidbcloud/AgentTeam/internal/store/storeerr"
)

var (
	ErrUnauthorized             = storeerr.ErrUnauthorized
	ErrForbidden                = storeerr.ErrForbidden
	ErrNotFound                 = storeerr.ErrNotFound
	ErrConflict                 = storeerr.ErrConflict
	ErrBadRequest               = storeerr.ErrBadRequest
	ErrGone                     = storeerr.ErrGone
	ErrSystemNotInitialized     = storeerr.ErrSystemNotInitialized
	ErrSystemAlreadyInitialized = storeerr.ErrSystemAlreadyInitialized
)

func badRequest(message string) error { return storeerr.BadRequest(message) }
func forbidden(message string) error  { return storeerr.Forbidden(message) }
func notFound(message string) error   { return storeerr.NotFound(message) }
func conflict(message string) error   { return storeerr.Conflict(message) }
func gone(message string) error       { return storeerr.Gone(message) }

func uniqueViolationConstraint(err error) (string, bool) {
	return coredb.UniqueViolationConstraint(err)
}

// User is the identity-domain user projection shared with API ports.
type User = model.User

// UserSession is the identity-domain session projection shared with API ports.
type UserSession = model.UserSession

// MobileSession is the identity-domain mobile login projection shared with API ports.
type MobileSession = model.MobileSession

type Options struct {
	RequireSystemAdminUser func(context.Context, string) error
}

type Store struct {
	db      coredb.DB
	options Options
}

func New(db coredb.DB, options Options) *Store {
	return &Store{db: db, options: options}
}

func (s *Store) Validate() error { return s.options.Validate() }

func (o Options) Validate() error {
	var missing []string
	if o.RequireSystemAdminUser == nil {
		missing = append(missing, "RequireSystemAdminUser")
	}
	if len(missing) > 0 {
		return fmt.Errorf("identity store: missing dependencies: %s", strings.Join(missing, ", "))
	}
	return nil
}

func (store *Store) requireSystemAdminUser(ctx context.Context, userID string) error {
	if store == nil || store.options.RequireSystemAdminUser == nil {
		return fmt.Errorf("identity store system admin authorization dependency is not configured")
	}
	return store.options.RequireSystemAdminUser(ctx, userID)
}

func loadUserWithoutPasswordHash(ctx context.Context, queryer coredb.QueryRower, userID string) (model.User, error) {
	row := queryer.QueryRow(ctx, `
SELECT id, COALESCE(email, ''), COALESCE(mobile, ''), name, display_name, avatar_url, is_admin, email_verified_at, mobile_verified_at, created_at, updated_at
FROM users
WHERE id = $1
`, userID)

	var user model.User
	if err := scanUserWithoutPasswordHash(row, &user); err != nil {
		return model.User{}, err
	}
	return user, nil
}

func scanUserWithoutPasswordHash(row coredb.Row, user *model.User) error {
	return row.Scan(
		&user.ID,
		&user.Email,
		&user.Mobile,
		&user.Name,
		&user.DisplayName,
		&user.AvatarURL,
		&user.IsAdmin,
		&user.EmailVerifiedAt,
		&user.MobileVerifiedAt,
		&user.CreatedAt,
		&user.UpdatedAt,
	)
}
