package client

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

	"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model"
	"git.faercol.me/faercol/polyculeconnect/polyculeconnect/logger"
	_ "github.com/mattn/go-sqlite3"
)

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

const clientRows = `"client"."id", "client"."secret", "client"."redirect_uris", "client"."trusted_peers", "client"."name"`

type ClientDB interface {
	GetClientByID(ctx context.Context, id string) (*model.Client, error)
}

type sqlClientDB struct {
	db *sql.DB
}

func strArrayToSlice(rawVal string) []string {
	var res []string
	if err := json.Unmarshal([]byte(rawVal), &res); err != nil {
		return nil
	}
	return res
}

func clientFromRow(row *sql.Row) (*model.Client, error) {
	var res model.Client
	redirectURIsStr := ""
	trustedPeersStr := ""

	if err := row.Scan(&res.ID, &res.Secret, &redirectURIsStr, &trustedPeersStr, &res.Name); err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, ErrNotFound
		}
		return nil, fmt.Errorf("invalid format for client: %w", err)
	}

	res.ClientConfig.RedirectURIs = strArrayToSlice(redirectURIsStr)
	res.ClientConfig.TrustedPeers = strArrayToSlice(trustedPeersStr)

	return &res, nil
}

func (db *sqlClientDB) GetClientByID(ctx context.Context, id string) (*model.Client, error) {
	logger.L.Debugf("Getting client app with ID %s from DB", id)
	query := fmt.Sprintf(`SELECT %s FROM "client" WHERE "id" = ?`, clientRows)
	row := db.db.QueryRowContext(ctx, query, id)
	return clientFromRow(row)
}

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