package db

import (
	"database/sql"
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	_ "github.com/lib/pq"
)

var PgDB *sql.DB

// ConnectPostgres PostgreSQL veritabanÄ±na baÄŸlanÄ±r.
func ConnectPostgres() (*sql.DB, error) {
	connStr := strings.TrimSpace(os.Getenv("POSTGRES_CONN"))
	if connStr == "" {
		return nil, fmt.Errorf("POSTGRES_CONN tanÄ±mlÄ± deÄŸil")
	}

	// Make DB writes attributable in Postgres audit triggers via current_setting('application_name').
	// Prefer setting it in POSTGRES_CONN, but default it here if missing.
	connStr = ensurePGApplicationName(connStr, strings.TrimSpace(os.Getenv("POSTGRES_APPLICATION_NAME")))

	db, err := sql.Open("postgres", connStr)
	if err != nil {
		return nil, fmt.Errorf("PostgreSQL baÄŸlantÄ± hatasÄ±: %w", err)
	}

	// BaÄŸlantÄ± havuzu ayarlarÄ± (audit log uyumlu).
	db.SetMaxOpenConns(30)
	db.SetMaxIdleConns(10)
	db.SetConnMaxLifetime(30 * time.Minute)
	db.SetConnMaxIdleTime(5 * time.Minute)

	// BaÄŸlantÄ±yÄ± test et.
	if err = db.Ping(); err != nil {
		// Some managed PostgreSQL servers require TLS. If the current DSN uses
		// sslmode=disable and server rejects with "no encryption", retry once
		// with sslmode=require to avoid startup failure.
		if strings.Contains(err.Error(), "no pg_hba.conf entry") &&
			strings.Contains(err.Error(), "no encryption") &&
			strings.Contains(strings.ToLower(connStr), "sslmode=disable") {
			secureConnStr := strings.Replace(connStr, "sslmode=disable", "sslmode=require", 1)
			secureConnStr = ensurePGApplicationName(secureConnStr, strings.TrimSpace(os.Getenv("POSTGRES_APPLICATION_NAME")))
			log.Println("PostgreSQL TLS gerektiriyor, sslmode=require ile tekrar deneniyor")

			_ = db.Close()
			db, err = sql.Open("postgres", secureConnStr)
			if err != nil {
				return nil, fmt.Errorf("PostgreSQL TLS retry open failed: %w", err)
			}

			db.SetMaxOpenConns(30)
			db.SetMaxIdleConns(10)
			db.SetConnMaxLifetime(30 * time.Minute)
			db.SetConnMaxIdleTime(5 * time.Minute)

			if err = db.Ping(); err != nil {
				return nil, fmt.Errorf("PostgreSQL eriÅŸilemiyor (TLS retry): %w", err)
			}
		} else {
			return nil, fmt.Errorf("PostgreSQL eriÅŸilemiyor: %w", err)
		}
	}

	log.Println("PostgreSQL baÄŸlantÄ±sÄ± baÅŸarÄ±lÄ±")
	PgDB = db
	return db, nil
}

func ensurePGApplicationName(connStr string, appName string) string {
	if strings.TrimSpace(appName) == "" {
		appName = "bssapp-backend"
	}
	low := strings.ToLower(connStr)
	if strings.Contains(low, "application_name=") {
		return connStr
	}

	// URL style DSN: postgres://...?... (lib/pq supports it)
	if strings.HasPrefix(low, "postgres://") || strings.HasPrefix(low, "postgresql://") {
		sep := "?"
		if strings.Contains(connStr, "?") {
			sep = "&"
		}
		return connStr + sep + "application_name=" + appName
	}

	// Keyword DSN: "host=... user=... dbname=... sslmode=..."
	return strings.TrimSpace(connStr) + " application_name=" + appName
}

// GetPostgresUsers test amaÃ§lÄ± ilk 5 kullanÄ±cÄ±yÄ± listeler.
func GetPostgresUsers(db *sql.DB) error {
	query := `SELECT id, code, email FROM mk_dfusr ORDER BY id LIMIT 5`
	rows, err := db.Query(query)
	if err != nil {
		return fmt.Errorf("PostgreSQL sorgu hatasÄ±: %w", err)
	}
	defer rows.Close()

	fmt.Println("Ä°lk 5 PostgreSQL kullanÄ±cÄ±sÄ±:")
	for rows.Next() {
		var id int
		var code, email string
		if err := rows.Scan(&id, &code, &email); err != nil {
			return err
		}
		fmt.Printf("  -> ID: %-4d | USER: %-20s | EMAIL: %s\n", id, code, email)
	}

	return rows.Err()
}
