// Package user 定义用户与会话的领域类型，以及 user 模块对外暴露的 Service 接口契约。
//
// 本文件仅做类型声明，不包含任何业务实现；Login/Logout/ResolveSession 等
// 方法在后续步骤（E6 等）实装。Service 接口的方法集刻意覆盖了
// transport/http/middleware.SessionResolver 的方法签名，因此 Service 的
// 任意实现都可直接作为 SessionResolver 注入到 Auth 中间件，避免在装配层
// 再写一层适配。
package user

import (
	"context"
	"time"

	"github.com/google/uuid"
)

// User 表示一个本地账号。字段与 sqlc 生成的行模型一一对应，但使用领域语义
// 类型（uuid.UUID / time.Time）而非 pgtype.*，便于上层逻辑直接使用而无需
// 关心驱动层的可空封装。
type User struct {
	ID           uuid.UUID
	Email        string
	DisplayName  string
	IsAdmin      bool
	Enabled      bool
	PasswordHash string
	CreatedAt    time.Time
	UpdatedAt    time.Time
}

// Session 表示一条已颁发但尚未失效的登录会话。TokenHash 存放原始 token 的
// SHA-256 摘要，原文仅在登录响应时返回一次；服务端不持久化明文 token，
// 因此校验时必须重新计算摘要再比对。LastSeenAt 为可空字段（首次创建后
// 尚未被使用过时为 nil）。
type Session struct {
	ID         uuid.UUID
	UserID     uuid.UUID
	TokenHash  []byte // sha256(token)
	ExpiresAt  time.Time
	LastSeenAt *time.Time
	CreatedAt  time.Time
}

// Service 是 user 模块对外暴露的应用服务契约。它同时满足
// transport/http/middleware.SessionResolver 接口（参见 ResolveSession 方法），
// 因此可以直接被 Auth 中间件复用。
type Service interface {
	// Login 校验邮箱密码，成功后签发新会话；返回的 token 为原文，仅此一次可见。
	Login(ctx context.Context, email, password, ip string) (token string, user *User, err error)
	// Logout 注销给定 token 对应的会话；token 未知或已过期时返回 nil（幂等）。
	Logout(ctx context.Context, token string) error
	// ResolveSession 将 bearer token 解析为已认证的用户 ID，实现
	// middleware.SessionResolver 接口契约：合法且未过期返回 (uid,true,nil)；
	// 语法合法但未知/过期返回 (uuid.Nil,false,nil)；底层故障返回非 nil error。
	ResolveSession(ctx context.Context, token string) (uuid.UUID, bool, error)
	// Get 按主键加载用户，未找到时返回 errs.NotFound（在 E6 实装时确定）。
	Get(ctx context.Context, id uuid.UUID) (*User, error)
	// Bootstrap 在系统首次启动时创建初始管理员账号，已存在同邮箱用户时为幂等。
	Bootstrap(ctx context.Context, email, password string) (*User, error)
	// ListAdmins 返回所有管理员用户，供内部模块（如 jobs runner）使用。
	ListAdmins(ctx context.Context) ([]*User, error)

	// ===== 管理员用户管理（需调用方自行做 admin 鉴权）=====

	// ListUsers 返回全部用户，按创建时间升序，供管理后台展示。
	ListUsers(ctx context.Context) ([]*User, error)
	// CreateUser 由管理员创建一个新账号。email 唯一冲突时返回 CodeConflict。
	CreateUser(ctx context.Context, in CreateUserInput) (*User, error)
	// UpdateProfile 修改用户的 display_name。
	UpdateProfile(ctx context.Context, id uuid.UUID, displayName string) (*User, error)
	// SetAdmin 设置用户的管理员标志。降级最后一个启用管理员时返回 CodeConflict；
	// actor==target 且降级自身时返回 CodeConflict（防自锁）。
	SetAdmin(ctx context.Context, actor, target uuid.UUID, isAdmin bool) (*User, error)
	// SetEnabled 启用/禁用用户。禁用会撤销其全部会话。禁用最后一个启用管理员或
	// 禁用自身时返回 CodeConflict。
	SetEnabled(ctx context.Context, actor, target uuid.UUID, enabled bool) (*User, error)
	// AdminResetPassword 由管理员重置目标用户密码，返回一次性明文临时密码并撤销其会话。
	AdminResetPassword(ctx context.Context, id uuid.UUID) (tempPassword string, err error)
	// ChangePassword 用户自助改密：校验旧密码后更新，并撤销其它会话。
	ChangePassword(ctx context.Context, id uuid.UUID, oldPassword, newPassword string) error
	// DeleteUser 删除用户。删除最后一个启用管理员或删除自身时返回 CodeConflict。
	DeleteUser(ctx context.Context, actor, target uuid.UUID) error
}

// CreateUserInput 是管理员创建用户的入参。
type CreateUserInput struct {
	Email       string
	DisplayName string
	Password    string
	IsAdmin     bool
}
