package user

import (
	"context"
	"database/sql"
	"errors"
	"time"
)

// User مدل کاربر.
type User struct {
	ID        int64     `json:"id"`
	Mobile    string    `json:"mobile"`
	FirstName *string   `json:"first_name"`
	LastName  *string   `json:"last_name"`
	Avatar    *string   `json:"avatar"`
	Coins     int64     `json:"coins"`
	IsAdmin   bool      `json:"is_admin"`
	CreatedAt time.Time `json:"created_at"`
}

var ErrNotFound = errors.New("user not found")

// Repo دسترسی به جدول users.
type Repo struct{ db *sql.DB }

func NewRepo(db *sql.DB) *Repo { return &Repo{db: db} }

// FindByMobile کاربر را با شماره موبایل پیدا می‌کند.
func (r *Repo) FindByMobile(ctx context.Context, mobile string) (*User, error) {
	row := r.db.QueryRowContext(ctx,
		`SELECT id, mobile, first_name, last_name, avatar, coins, is_admin, created_at
		 FROM users WHERE mobile = ?`, mobile)
	return scan(row)
}

// FindByID کاربر را با شناسه پیدا می‌کند.
func (r *Repo) FindByID(ctx context.Context, id int64) (*User, error) {
	row := r.db.QueryRowContext(ctx,
		`SELECT id, mobile, first_name, last_name, avatar, coins, is_admin, created_at
		 FROM users WHERE id = ?`, id)
	return scan(row)
}

// Create کاربر جدید می‌سازد.
func (r *Repo) Create(ctx context.Context, mobile string) (*User, error) {
	res, err := r.db.ExecContext(ctx, `INSERT INTO users (mobile) VALUES (?)`, mobile)
	if err != nil {
		return nil, err
	}
	id, _ := res.LastInsertId()
	return r.FindByID(ctx, id)
}

// UpdateProfile نام نمایشی و آواتار کاربر را تنظیم می‌کند.
func (r *Repo) UpdateProfile(ctx context.Context, id int64, firstName, avatar string) error {
	_, err := r.db.ExecContext(ctx,
		`UPDATE users SET first_name = ?, avatar = ? WHERE id = ?`,
		firstName, avatar, id)
	return err
}

// FindOrCreate اگر کاربر نبود می‌سازد (مطابق فلوی login-otp).
func (r *Repo) FindOrCreate(ctx context.Context, mobile string) (*User, error) {
	u, err := r.FindByMobile(ctx, mobile)
	if errors.Is(err, ErrNotFound) {
		return r.Create(ctx, mobile)
	}
	return u, err
}

func scan(row *sql.Row) (*User, error) {
	var u User
	var created string
	err := row.Scan(&u.ID, &u.Mobile, &u.FirstName, &u.LastName, &u.Avatar, &u.Coins, &u.IsAdmin, &created)
	if errors.Is(err, sql.ErrNoRows) {
		return nil, ErrNotFound
	}
	if err != nil {
		return nil, err
	}
	u.CreatedAt, _ = time.Parse("2006-01-02 15:04:05", created)
	return &u, nil
}
