package jdbc

import (
	"context"
	"errors"
	"fmt"
	"strings"

	_ "github.com/lib/pq"
)

type postgresJDBC struct {
	conn   string
	params map[string]string
}

func (s *postgresJDBC) ping(ctx context.Context) bool {
	// try the provided connection string directly
	if ping(ctx, "postgres", s.conn) {
		return true
	}
	// try as a URL
	if ping(ctx, "postgres", "postgres://"+s.conn) {
		return true
	}
	// build a connection string
	data := map[string]string{
		// default user
		"user": "postgres",
	}
	for key, val := range s.params {
		if key == "host" {
			if h, p, found := strings.Cut(val, ":"); found {
				data["host"] = h
				data["port"] = p
				continue
			}
		}
		data[key] = val
	}
	if ping(ctx, "postgres", joinKeyValues(data, " ")) {
		return true
	}
	if s.params["dbname"] != "" {
		delete(s.params, "dbname")
		return s.ping(ctx)
	}
	return false
}

func joinKeyValues(m map[string]string, sep string) string {
	var data []string
	for k, v := range m {
		if v == "" {
			continue
		}
		data = append(data, fmt.Sprintf("%s=%s", k, v))
	}
	return strings.Join(data, sep)
}

func parsePostgres(subname string) (jdbc, error) {
	// expected form: //HOST/DB?key=value&key=value
	hostAndDB, paramString, _ := strings.Cut(subname, "?")
	if !strings.HasPrefix(hostAndDB, "//") {
		return nil, errors.New("expected host to start with //")
	}
	hostAndDB = strings.TrimPrefix(hostAndDB, "//")
	host, database, _ := strings.Cut(hostAndDB, "/")

	params := map[string]string{
		"host":   host,
		"dbname": database,
	}
	for _, param := range strings.Split(paramString, "&") {
		key, val, _ := strings.Cut(param, "=")
		params[key] = val
	}

	return &postgresJDBC{subname[2:], params}, nil
}
