package db

import (
	"context"
	"database/sql"
	"fmt"
	"log/slog"
	"strings"

	"git.maximotejeda.com/maximo/tgb-user/internal/application/core/domain"
)

type User struct {
	db        *sql.DB
	log       *slog.Logger
	ID        int64  `json:"id"`
	Tgb_ID    int64  `json:"tgb_id"`
	Username  string `json:"username"`
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Created   int64  `json:"created"`
	Edited    int64  `json:"edited"`
	Deleted   int64  `json:"deleted"`
}

func NewUser(db *sql.DB, log *slog.Logger) *User {
	log = log.With("obj", "User")
	return &User{
		db:  db,
		log: log,
	}
}

func (u User) Get(ctx context.Context, tgb_id int64) (*domain.User, error) {
	stmt, err := u.db.PrepareContext(ctx,
		`
SELECT u.id, u.tgb_id, u.username, u.first_name, u.last_name, u.created, u.edited
  FROM users AS u
     WHERE u.tgb_id = ? AND deleted IS NULL;
`)
	if err != nil {
		u.log.Error("prepare stmt get", "error", err)
		return nil, err
	}
	defer stmt.Close()
	us := &domain.User{}
	if err := stmt.QueryRowContext(ctx, tgb_id).Scan(&us.ID, &us.TGB_ID, &us.Username, &us.FirstName, &us.LastName, &us.Created, &us.Edited); err != nil {
		u.log.Error("query row context get", "error", err)
		return nil, err
	}
	bu := NewBotUser(u.db, u.log)
	bul, err := bu.GetBots(ctx, us.TGB_ID)
	if err != nil {
		u.log.Error("getting bots", "error", err)
	}
	for _, i := range bul {
		us.TGBOT = us.TGBOT + "," + i.BotName
	}
	us.TGBOT, _ = strings.CutPrefix(us.TGBOT, ",")
	return us, nil
}

func (u User) Create(ctx context.Context, user *domain.User) (bool, error) {
	stmt, err := u.db.PrepareContext(ctx,
		`
INSERT INTO users (tgb_id, username, first_name, last_name, created, edited)
VALUES(?,?,?,?,strftime('%s', 'now'),strftime('%s', 'now'));
`)
	if err != nil {
		u.log.Error("prepare stmt create", "error", err)
		return false, err
	}
	defer stmt.Close()
	_, err = stmt.ExecContext(ctx, user.TGB_ID, user.Username, user.FirstName, user.LastName)
	if err != nil {
		u.log.Error("exec context create", "error", err)
		return false, err
	}
	return true, nil

}
func (u User) Edit(ctx context.Context, user domain.User) (bool, error) {
	stmt, err := u.db.PrepareContext(ctx,
		`
UPDATE users
    SET username = ?,
        first_name = ?,
        last_name = ?,
        edited = strftime('%s', 'now')
    WHERE
        tgb_id = ? AND deleted IS NULL;
`)
	if err != nil {
		u.log.Error("prepare stmt edit", "error", err)
		return false, err
	}
	defer stmt.Close()
	row, err := stmt.ExecContext(ctx, user.Username, user.FirstName, user.LastName, user.TGB_ID)
	if err != nil {
		u.log.Error("exec context edit", "error", err)
		return false, nil
	}

	num, _ := row.RowsAffected()
	if num < 1 {
		return false, fmt.Errorf("no rows affected with tgb_id: %d", user.TGB_ID)
	}
	return true, nil

}
func (u User) Delete(ctx context.Context, tgb_id int64) (bool, error) {
	stmt, err := u.db.PrepareContext(ctx, `
UPDATE users
SET deleted = strftime('%s', 'now'),
edited = strftime('%s', 'now')
WHERE tgb_id = ?;
`)
	if err != nil {
		u.log.Error("prepare stmt delete", "error", err)
		return false, err
	}
	defer stmt.Close()
	_, err = stmt.ExecContext(ctx, tgb_id)
	if err != nil {
		u.log.Error("exec context delete", "error", err)
		return false, err
	}
	return true, nil
}

func (u User) HardDelete(ctx context.Context, tgb_id int64) (bool, error) {
	stmt, err := u.db.PrepareContext(ctx, `
DELETE FROM users
WHERE tgb_id = ?;
`)
	if err != nil {
		u.log.Error("prepare stmt hard delete", "error", err)
		return false, err
	}
	defer stmt.Close()
	_, err = stmt.ExecContext(ctx, tgb_id)
	if err != nil {
		u.log.Error("exec context hard delete", "error", err)
		return false, err
	}
	return true, nil
}
func (u User) AddBot(ctx context.Context, tgb_id int64, bot_name string) (bool, error) {
	bu := BotUser{db: u.db}
	ok, err := bu.Add(ctx, tgb_id, bot_name)
	return ok, err
}
func (u User) DeleteBot(ctx context.Context, tgb_id int64, bot_name string) (bool, error) {
	bu := BotUser{db: u.db}
	ok, err := bu.Delete(ctx, tgb_id, bot_name)
	return ok, err
}
