package postgresql

import (
	"context"
	"fmt"
	"log"

	"github.com/jackc/pgx/v5"

	"github.com/alexedwards/argon2id"
	"github.com/stripe/stripe-go/v83"
	"github.com/stripe/stripe-go/v83/customer"

	"alfheimgame.com/alfheim/pkg/models"
)

type AccountModel struct {
	DB *pgx.Conn
}

func (m *AccountModel) Insert(username string, password string, firstname string, lastname string, email string) (int32, error) {

	//hashedpassword, err := bcrypt.GenerateFromPassword([]byte(password), 12)
	hashedpassword, err := argon2id.CreateHash(password, argon2id.DefaultParams)

	if err != nil {
		log.Println(err)
		return 0, err
	}

	//log.Println(hashedpassword)
	stmt := `INSERT INTO accounts (username, password, firstname, lastname, email) VALUES ($1, $2, $3, $4, $5) RETURNING id`

	var insertid int32

	err = m.DB.QueryRow(context.Background(), stmt, username, string(hashedpassword), firstname, lastname, email).Scan(&insertid)
	if err != nil {
		log.Println(err)
		return 0, err
	}

	params := &stripe.CustomerParams{
		Name:  stripe.String(fmt.Sprintf("%s %s", firstname, lastname)),
		Email: stripe.String(email),
	}
	customer, err := customer.New(params)

	if err != nil {
		log.Println(err)
		return 0, err
	}

	stmt = `UPDATE accounts SET stripe_id = $1 WHERE id = $2`

	_, err = m.DB.Exec(context.Background(), stmt, customer.ID, insertid)
	if err != nil {
		log.Println(err)
		return 0, err
	}

	return insertid, nil
}

func (m *AccountModel) Delete(id int32) error {
	account, err := m.GetAccount(id)

	if err != nil {
		log.Println(err)
		return err
	}

	if account.StripeID != "" {
		/*result*/ _, err := customer.Del(account.StripeID, nil)
		if err != nil {
			log.Println(err)
		}
		//log.Println(result)
	}

	stmt := `DELETE FROM accounts WHERE id = $1`

	_, err = m.DB.Exec(context.Background(), stmt, id)
	if err != nil {
		log.Println(err)
	}

	return nil
}

func (m *AccountModel) GetAccount(id int32) (models.Account, error) {
	if id == 0 {
		return models.Account{}, models.ErrNoRecord
	}

	var account models.Account
	stmt := `SELECT id, username, password, colour, firstname, lastname, email, created, stripe_id FROM accounts WHERE id = $1`
	err := m.DB.QueryRow(context.Background(), stmt, id).Scan(&account.ID, &account.Username, &account.Password, &account.Colour, &account.Firstname, &account.Lastname, &account.Email, &account.Created, &account.StripeID)

	if err == pgx.ErrNoRows {
		return models.Account{}, pgx.ErrNoRows
	} else if err != nil {
		return models.Account{}, err
	}

	return account, nil
}

func (m *AccountModel) Authenticate(username string, password string) (int32, error) {
	var id int32
	var hashedpassword string
	stmt := `SELECT id, password FROM accounts WHERE username = $1`
	err := m.DB.QueryRow(context.Background(), stmt, username).Scan(&id, &hashedpassword)
	if err == pgx.ErrNoRows {
		return 0, models.ErrInvalidCredentials
	}

	match, err := argon2id.ComparePasswordAndHash(password, hashedpassword)
	if !match {
		return 0, models.ErrInvalidCredentials
	} else if err != nil {
		return 0, err
	}

	return id, nil
}

func (m *AccountModel) ExistsAccount(id int32) bool {
	var exists bool
	stmt := `SELECT EXISTS(SELECT 1 FROM accounts WHERE id = $1)`
	err := m.DB.QueryRow(context.Background(), stmt, id).Scan(&exists)
	if err != nil {
		log.Println(err)
	}

	//log.Println(exists)

	return exists
}
