package authcode

import (
	"context"
	"database/sql"
	"errors"
	"fmt"

	"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model"
	"git.faercol.me/faercol/polyculeconnect/polyculeconnect/logger"
)

var ErrNotFound = errors.New("auth code not found")

type AuthCodeDB interface {
	GetAuthCodeByCode(ctx context.Context, code string) (*model.AuthCode, error)
	CreateAuthCode(ctx context.Context, code model.AuthCode) error
}

type sqlAuthCodeDB struct {
	db *sql.DB
}

func (db *sqlAuthCodeDB) CreateAuthCode(ctx context.Context, code model.AuthCode) error {
	logger.L.Debugf("Creating auth code for request %s", code.RequestID)
	tx, err := db.db.BeginTx(ctx, nil)
	if err != nil {
		return fmt.Errorf("failed to start transaction: %w", err)
	}
	defer func() { _ = tx.Rollback() }()

	query := `INSERT INTO "auth_code_2" ("id", "auth_request_id", "code") VALUES ($1, $2, $3)`
	_, err = tx.ExecContext(ctx, query, code.CodeID, code.RequestID, code.Code)
	if err != nil {
		return fmt.Errorf("failed to insert in DB: %w", err)
	}

	if err := tx.Commit(); err != nil {
		return fmt.Errorf("failed to commit transaction: %w", err)
	}
	return nil
}

func (db *sqlAuthCodeDB) GetAuthCodeByCode(ctx context.Context, code string) (*model.AuthCode, error) {
	logger.L.Debugf("Getting auth code %s from DB", code)
	query := `SELECT "id", "auth_request_id", "code" FROM "auth_code_2" WHERE "code" = ?`
	row := db.db.QueryRowContext(ctx, query, code)

	var res model.AuthCode
	if err := row.Scan(&res.CodeID, &res.RequestID, &res.Code); err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, ErrNotFound
		}
		return nil, fmt.Errorf("failed to read row from DB: %w", err)
	}

	return &res, nil
}

func New(db *sql.DB) AuthCodeDB {
	return &sqlAuthCodeDB{db: db}
}
