// Package db provides metadb provisioning for cp9 local development environments.
package db

import (
	"context"
	"fmt"
	"net"
	"strconv"

	"github.com/go-sql-driver/mysql"

	"github.com/tidbcloud/controlplane9/internal/config"
)

// Provider abstracts database instance provisioning.
// Each implementation (Zero, Starter, local MySQL) satisfies this interface.
type Provider interface {
	// Name returns the provider identifier (e.g. "tidb-cloud-zero").
	Name() config.DatabaseProvider

	// Provision creates a new database instance.
	// Returns an Instance with connection details.
	Provision(ctx context.Context) (*Instance, error)

	// CreateDatabase creates a named database within the instance.
	CreateDatabase(ctx context.Context, inst *Instance, dbName string) error

	// Destroy deletes the database instance.
	Destroy(ctx context.Context, inst *Instance) error
}

// Instance represents a provisioned database instance.
type Instance struct {
	Provider   config.DatabaseProvider `json:"provider"`
	ID         string                  `json:"id"`
	Host       string                  `json:"host"`
	Port       int                     `json:"port"`
	User       string                  `json:"user"`
	Password   string                  `json:"password"`
	CACertPath string                  `json:"ca_cert_path,omitempty"`
}

// DSN returns a MySQL-compatible DSN for a specific database within the instance.
// Uses mysql.Config.FormatDSN() to safely encode credentials and parameters.
func (inst *Instance) DSN(database string) string {
	cfg := mysql.Config{
		User:                 inst.User,
		Passwd:               inst.Password,
		Net:                  "tcp",
		Addr:                 net.JoinHostPort(inst.Host, strconv.Itoa(inst.Port)),
		DBName:               database,
		AllowNativePasswords: true,
	}

	// TiDB Cloud requires TLS; local MySQL does not.
	if inst.Provider != config.DBLocalMySQL {
		cfg.TLSConfig = "true"
	}

	return cfg.FormatDSN()
}

// ProvisionResult is the structured output for db provisioning.
type ProvisionResult struct {
	Provider  config.DatabaseProvider `json:"provider"`
	ID        string                  `json:"instance_id"`
	Host      string                  `json:"host"`
	Port      int                     `json:"port"`
	Databases []string                `json:"databases"`
}

// FormatText implements model.TextFormatter.
func (r *ProvisionResult) FormatText() string {
	return fmt.Sprintf("db: provisioned %s instance=%s host=%s:%d databases=%d",
		r.Provider, r.ID, r.Host, r.Port, len(r.Databases))
}

// DestroyResult is the structured output for db destruction.
type DestroyResult struct {
	Provider config.DatabaseProvider `json:"provider"`
	ID       string                  `json:"instance_id"`
}

// FormatText implements model.TextFormatter.
func (r DestroyResult) FormatText() string {
	return fmt.Sprintf("db: destroyed %s instance=%s", r.Provider, r.ID)
}
