package db

import (
	"database/sql"
	"fmt"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	_ "github.com/microsoft/go-mssqldb"
)

var MssqlDB *sql.DB
var UretimDB *sql.DB

func envInt(name string, fallback int) int {
	raw := strings.TrimSpace(os.Getenv(name))
	if raw == "" {
		return fallback
	}
	value, err := strconv.Atoi(raw)
	if err != nil || value <= 0 {
		return fallback
	}
	return value
}

func ensureTimeoutValue(current string, desired int) string {
	cur, err := strconv.Atoi(strings.TrimSpace(current))
	if err == nil && cur >= desired {
		return strings.TrimSpace(current)
	}
	return strconv.Itoa(desired)
}

func ensureMSSQLTimeouts(connString string, connectionTimeoutSec int, dialTimeoutSec int) string {
	raw := strings.TrimSpace(connString)
	if raw == "" {
		return raw
	}

	if strings.HasPrefix(strings.ToLower(raw), "sqlserver://") {
		u, err := url.Parse(raw)
		if err != nil {
			return raw
		}
		q := u.Query()
		q.Set("connection timeout", ensureTimeoutValue(q.Get("connection timeout"), connectionTimeoutSec))
		q.Set("dial timeout", ensureTimeoutValue(q.Get("dial timeout"), dialTimeoutSec))
		u.RawQuery = q.Encode()
		return u.String()
	}

	parts := strings.Split(raw, ";")
	foundConnectionTimeout := false
	foundDialTimeout := false

	for i, part := range parts {
		part = strings.TrimSpace(part)
		if part == "" {
			continue
		}

		eq := strings.Index(part, "=")
		if eq <= 0 {
			continue
		}

		key := strings.ToLower(strings.TrimSpace(part[:eq]))
		value := strings.TrimSpace(part[eq+1:])

		switch key {
		case "connection timeout":
			foundConnectionTimeout = true
			parts[i] = "connection timeout=" + ensureTimeoutValue(value, connectionTimeoutSec)
		case "dial timeout":
			foundDialTimeout = true
			parts[i] = "dial timeout=" + ensureTimeoutValue(value, dialTimeoutSec)
		}
	}

	if !foundConnectionTimeout {
		parts = append(parts, "connection timeout="+strconv.Itoa(connectionTimeoutSec))
	}
	if !foundDialTimeout {
		parts = append(parts, "dial timeout="+strconv.Itoa(dialTimeoutSec))
	}

	return strings.Join(parts, ";")
}

// ConnectMSSQL initializes the MSSQL connection from environment.
func ConnectMSSQL() error {
	connString := strings.TrimSpace(os.Getenv("MSSQL_CONN"))
	if connString == "" {
		return fmt.Errorf("MSSQL_CONN tanimli degil")
	}

	connectionTimeoutSec := envInt("MSSQL_CONNECTION_TIMEOUT_SEC", 120)
	dialTimeoutSec := envInt("MSSQL_DIAL_TIMEOUT_SEC", connectionTimeoutSec)
	connString = ensureMSSQLTimeouts(connString, connectionTimeoutSec, dialTimeoutSec)

	var err error
	MssqlDB, err = sql.Open("sqlserver", connString)
	if err != nil {
		return fmt.Errorf("MSSQL baglanti hatasi: %w", err)
	}

	MssqlDB.SetMaxOpenConns(envInt("MSSQL_MAX_OPEN_CONNS", 40))
	MssqlDB.SetMaxIdleConns(envInt("MSSQL_MAX_IDLE_CONNS", 40))
	MssqlDB.SetConnMaxLifetime(time.Duration(envInt("MSSQL_CONN_MAX_LIFETIME_MIN", 30)) * time.Minute)
	MssqlDB.SetConnMaxIdleTime(time.Duration(envInt("MSSQL_CONN_MAX_IDLE_MIN", 10)) * time.Minute)

	if err = MssqlDB.Ping(); err != nil {
		return fmt.Errorf("MSSQL erisilemiyor: %w", err)
	}

	fmt.Printf("MSSQL baglantisi basarili (connection timeout=%ds, dial timeout=%ds)\n", connectionTimeoutSec, dialTimeoutSec)
	return nil
}

func GetDB() *sql.DB {
	return MssqlDB
}

// ConnectMSSQLUretim initializes the URETIM MSSQL connection from environment.
func ConnectMSSQLUretim() error {
	connString := strings.TrimSpace(os.Getenv("URETIM_MSSQL_CONN"))
	if connString == "" {
		return fmt.Errorf("URETIM_MSSQL_CONN tanimli degil")
	}

	connectionTimeoutSec := envInt("URETIM_MSSQL_CONNECTION_TIMEOUT_SEC", envInt("MSSQL_CONNECTION_TIMEOUT_SEC", 120))
	dialTimeoutSec := envInt("URETIM_MSSQL_DIAL_TIMEOUT_SEC", connectionTimeoutSec)
	connString = ensureMSSQLTimeouts(connString, connectionTimeoutSec, dialTimeoutSec)

	var err error
	UretimDB, err = sql.Open("sqlserver", connString)
	if err != nil {
		return fmt.Errorf("URETIM MSSQL baglanti hatasi: %w", err)
	}

	UretimDB.SetMaxOpenConns(envInt("URETIM_MSSQL_MAX_OPEN_CONNS", envInt("MSSQL_MAX_OPEN_CONNS", 40)))
	UretimDB.SetMaxIdleConns(envInt("URETIM_MSSQL_MAX_IDLE_CONNS", envInt("MSSQL_MAX_IDLE_CONNS", 40)))
	UretimDB.SetConnMaxLifetime(time.Duration(envInt("URETIM_MSSQL_CONN_MAX_LIFETIME_MIN", envInt("MSSQL_CONN_MAX_LIFETIME_MIN", 30))) * time.Minute)
	UretimDB.SetConnMaxIdleTime(time.Duration(envInt("URETIM_MSSQL_CONN_MAX_IDLE_MIN", envInt("MSSQL_CONN_MAX_IDLE_MIN", 10))) * time.Minute)

	if err = UretimDB.Ping(); err != nil {
		return fmt.Errorf("URETIM MSSQL erisilemiyor: %w", err)
	}

	fmt.Printf("URETIM MSSQL baglantisi basarili (connection timeout=%ds, dial timeout=%ds)\n", connectionTimeoutSec, dialTimeoutSec)
	return nil
}

func GetUretimDB() *sql.DB {
	return UretimDB
}
