package namespacecmd

import (
	"bufio"
	"crypto/tls"
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"

	"github.com/DeBrosOfficial/network/pkg/auth"
	"github.com/spf13/cobra"
)

var rqliteCmd = &cobra.Command{
	Use:   "rqlite",
	Short: "Manage the namespace's internal RQLite database",
	Long:  "Export and import the namespace's internal RQLite database (stores deployments, DNS records, API keys, etc.).",
}

var rqliteExportCmd = &cobra.Command{
	Use:   "export",
	Short: "Export the namespace's RQLite database to a local SQLite file",
	Long:  "Downloads a consistent SQLite snapshot of the namespace's internal RQLite database.",
	RunE:  rqliteExport,
}

var rqliteImportCmd = &cobra.Command{
	Use:   "import",
	Short: "Import a SQLite dump into the namespace's RQLite (DESTRUCTIVE)",
	Long: `Replaces the namespace's entire RQLite database with the contents of the provided SQLite file.

WARNING: This is a destructive operation. All existing data in the namespace's RQLite
(deployments, DNS records, API keys, etc.) will be replaced with the imported file.`,
	RunE: rqliteImport,
}

func init() {
	rqliteExportCmd.Flags().StringP("output", "o", "", "Output file path (default: rqlite-export.db)")

	rqliteImportCmd.Flags().StringP("input", "i", "", "Input SQLite file path")
	_ = rqliteImportCmd.MarkFlagRequired("input")

	rqliteCmd.AddCommand(rqliteExportCmd)
	rqliteCmd.AddCommand(rqliteImportCmd)

	Cmd.AddCommand(rqliteCmd)
}

func rqliteExport(cmd *cobra.Command, args []string) error {
	output, _ := cmd.Flags().GetString("output")
	if output == "" {
		output = "rqlite-export.db"
	}

	apiURL := nsRQLiteAPIURL()
	token, err := nsRQLiteAuthToken()
	if err != nil {
		return err
	}

	url := apiURL + "/v1/rqlite/export"

	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return fmt.Errorf("failed to create request: %w", err)
	}
	req.Header.Set("Authorization", "Bearer "+token)

	client := &http.Client{
		Timeout: 0,
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
	}

	fmt.Printf("Exporting RQLite database to %s...\n", output)

	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("failed to connect to gateway: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("export failed (HTTP %d): %s", resp.StatusCode, string(body))
	}

	outFile, err := os.Create(output)
	if err != nil {
		return fmt.Errorf("failed to create output file: %w", err)
	}
	defer outFile.Close()

	written, err := io.Copy(outFile, resp.Body)
	if err != nil {
		os.Remove(output)
		return fmt.Errorf("failed to write export file: %w", err)
	}

	fmt.Printf("Export complete: %s (%d bytes)\n", output, written)
	return nil
}

func rqliteImport(cmd *cobra.Command, args []string) error {
	input, _ := cmd.Flags().GetString("input")

	info, err := os.Stat(input)
	if err != nil {
		return fmt.Errorf("cannot access input file: %w", err)
	}
	if info.IsDir() {
		return fmt.Errorf("input path is a directory, not a file")
	}

	store, err := auth.LoadEnhancedCredentials()
	if err != nil {
		return fmt.Errorf("failed to load credentials: %w", err)
	}
	gatewayURL := auth.GetDefaultGatewayURL()
	creds := store.GetDefaultCredential(gatewayURL)
	if creds == nil || !creds.IsValid() {
		return fmt.Errorf("not authenticated. Run 'orama auth login' first")
	}

	namespace := creds.Namespace
	if namespace == "" {
		namespace = "default"
	}

	fmt.Printf("WARNING: This will REPLACE the entire RQLite database for namespace '%s'.\n", namespace)
	fmt.Printf("All existing data (deployments, DNS records, API keys, etc.) will be lost.\n")
	fmt.Printf("Importing from: %s (%d bytes)\n\n", input, info.Size())
	fmt.Printf("Type the namespace name '%s' to confirm: ", namespace)

	scanner := bufio.NewScanner(os.Stdin)
	scanner.Scan()
	confirmation := strings.TrimSpace(scanner.Text())
	if confirmation != namespace {
		return fmt.Errorf("aborted - namespace name did not match")
	}

	apiURL := nsRQLiteAPIURL()
	token, err := nsRQLiteAuthToken()
	if err != nil {
		return err
	}

	file, err := os.Open(input)
	if err != nil {
		return fmt.Errorf("failed to open input file: %w", err)
	}
	defer file.Close()

	url := apiURL + "/v1/rqlite/import"

	req, err := http.NewRequest(http.MethodPost, url, file)
	if err != nil {
		return fmt.Errorf("failed to create request: %w", err)
	}
	req.Header.Set("Authorization", "Bearer "+token)
	req.Header.Set("Content-Type", "application/octet-stream")
	req.ContentLength = info.Size()

	client := &http.Client{
		Timeout: 0,
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
	}

	fmt.Printf("Importing database...\n")

	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("failed to connect to gateway: %w", err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("import failed (HTTP %d): %s", resp.StatusCode, string(body))
	}

	fmt.Printf("Import complete. The namespace '%s' RQLite database has been replaced.\n", namespace)
	return nil
}

func nsRQLiteAPIURL() string {
	if url := os.Getenv("ORAMA_API_URL"); url != "" {
		return url
	}
	return auth.GetDefaultGatewayURL()
}

func nsRQLiteAuthToken() (string, error) {
	if token := os.Getenv("ORAMA_TOKEN"); token != "" {
		return token, nil
	}

	store, err := auth.LoadEnhancedCredentials()
	if err != nil {
		return "", fmt.Errorf("failed to load credentials: %w", err)
	}

	gatewayURL := auth.GetDefaultGatewayURL()
	creds := store.GetDefaultCredential(gatewayURL)
	if creds == nil {
		return "", fmt.Errorf("no credentials found for %s. Run 'orama auth login' to authenticate", gatewayURL)
	}

	if !creds.IsValid() {
		return "", fmt.Errorf("credentials expired for %s. Run 'orama auth login' to re-authenticate", gatewayURL)
	}

	return creds.APIKey, nil
}
