package pgdriver

import (
	
	
	
	
	
	
	
	
	
)

type Config struct {
	// Network type, either tcp or unix.
	// Default is tcp.
	Network string
	// TCP host:port or Unix socket depending on Network.
	Addr string
	// Dial timeout for establishing new connections.
	// Default is 5 seconds.
	DialTimeout time.Duration
	// Dialer creates new network connection and has priority over
	// Network and Addr options.
	Dialer func(ctx context.Context, network, addr string) (net.Conn, error)

	// TLS config for secure connections.
	TLSConfig *tls.Config

	User     string
	Password string
	Database string
	AppName  string

	// Timeout for socket reads. If reached, commands will fail
	// with a timeout instead of blocking.
	ReadTimeout time.Duration
	// Timeout for socket writes. If reached, commands will fail
	// with a timeout instead of blocking.
	WriteTimeout time.Duration
}

func () *Config {
	 := env("PGHOST", "localhost")
	 := env("PGPORT", "5432")

	 := &Config{
		Network:     "tcp",
		Addr:        net.JoinHostPort(, ),
		DialTimeout: 5 * time.Second,

		User:     env("PGUSER", "postgres"),
		Database: env("PGDATABASE", "postgres"),

		ReadTimeout:  10 * time.Second,
		WriteTimeout: 5 * time.Second,
	}

	.Dialer = func( context.Context, ,  string) (net.Conn, error) {
		 := &net.Dialer{
			Timeout:   .DialTimeout,
			KeepAlive: 5 * time.Minute,
		}
		return .DialContext(, , )
	}

	return 
}

type DriverOption func(*Connector)

func ( string) DriverOption {
	if  == "" {
		panic("addr is empty")
	}
	return func( *Connector) {
		.cfg.Addr = 
	}
}

func ( *tls.Config) DriverOption {
	return func( *Connector) {
		.cfg.TLSConfig = 
	}
}

func ( string) DriverOption {
	if  == "" {
		panic("user is empty")
	}
	return func( *Connector) {
		.cfg.User = 
	}
}

func ( string) DriverOption {
	return func( *Connector) {
		.cfg.Password = 
	}
}

func ( string) DriverOption {
	if  == "" {
		panic("database is empty")
	}
	return func( *Connector) {
		.cfg.Database = 
	}
}

func ( string) DriverOption {
	return func( *Connector) {
		.cfg.AppName = 
	}
}

func ( time.Duration) DriverOption {
	return func( *Connector) {
		.cfg.DialTimeout = 
		.cfg.ReadTimeout = 
		.cfg.WriteTimeout = 
	}
}

func ( time.Duration) DriverOption {
	return func( *Connector) {
		.cfg.DialTimeout = 
	}
}

func ( time.Duration) DriverOption {
	return func( *Connector) {
		.cfg.ReadTimeout = 
	}
}

func ( time.Duration) DriverOption {
	return func( *Connector) {
		.cfg.WriteTimeout = 
	}
}

func ( string) DriverOption {
	return func( *Connector) {
		,  := parseDSN()
		if  != nil {
			panic()
		}
		for ,  := range  {
			()
		}
	}
}

func ( string) ([]DriverOption, error) {
	,  := url.Parse()
	if  != nil {
		return nil, 
	}

	if .Scheme != "postgres" && .Scheme != "postgresql" {
		return nil, errors.New("pgdriver: invalid scheme: " + .Scheme)
	}

	,  := url.ParseQuery(.RawQuery)
	if  != nil {
		return nil, 
	}

	var  []DriverOption

	if .Host != "" {
		 := .Host
		if !strings.Contains(, ":") {
			 += ":5432"
		}
		 = append(, WithAddr())
	}
	if .User != nil {
		 = append(, WithUser(.User.Username()))
		if ,  := .User.Password();  {
			 = append(, WithPassword())
		}
	}
	if len(.Path) > 1 {
		 = append(, WithDatabase(.Path[1:]))
	}

	if  := .Get("application_name");  != "" {
		 = append(, WithApplicationName())
	}
	delete(, "application_name")

	if  := .Get("sslmode");  != "" {
		switch  {
		case "verify-ca", "verify-full":
			 = append(, WithTLSConfig(new(tls.Config)))
		case "allow", "prefer", "require":
			 = append(, WithTLSConfig(&tls.Config{InsecureSkipVerify: true}))
		case "disable":
			// no TLS config
		default:
			return nil, fmt.Errorf("pgdriver: sslmode '%s' is not supported", )
		}
	} else {
		 = append(, WithTLSConfig(&tls.Config{InsecureSkipVerify: true}))
	}
	delete(, "sslmode")

	for  := range  {
		return nil, fmt.Errorf("pgdriver: unsupported option=%q", )
	}

	return , nil
}

func (,  string) string {
	if  := os.Getenv();  != "" {
		return 
	}
	return 
}

// verify is a method to make sure if the config is legitimate
// in the case it detects any errors, it returns with a non-nil error
// it can be extended to check other parameters
func ( *Config) () error {
	if .User == "" {
		return errors.New("pgdriver: User option is empty (to configure, use WithUser).")
	}
	return nil
}