package queries

import (
	"bssapp-backend/models"
	"database/sql"
	"fmt"
	"github.com/google/uuid"
	"log"
	"strings"
	"time"
)

// ============================================================
// 🔥 UNIVERSAL DATETIME PARSER
// ============================================================
func parseDateTime(str string) (time.Time, error) {
	layouts := []string{
		"2006-01-02 15:04:05", // "2025-11-21 12:37:21"
		time.RFC3339,          // "2025-11-21T12:37:21Z"
		"2006-01-02",          // "2025-11-21"
	}
	for _, layout := range layouts {
		if t, err := time.Parse(layout, str); err == nil {
			return t, nil
		}
	}
	return time.Time{}, fmt.Errorf("datetime parse edilemedi: %s", str)
}

// ============================================================
// 📌 DATE (YYYY-MM-DD) → sql.NullTime
// ============================================================
func nullableDateString(ns models.NullString) sql.NullTime {
	if ns.Valid && strings.TrimSpace(ns.String) != "" {
		t, err := time.Parse("2006-01-02", ns.String)
		if err == nil {
			return sql.NullTime{Valid: true, Time: t}
		}
	}
	return sql.NullTime{}
}

// ============================================================
// 📌 TIME (HH:mm:ss) → sql.NullString
// ============================================================
func nullableTimeString(ns models.NullString) sql.NullString {
	if ns.Valid && strings.TrimSpace(ns.String) != "" {
		return sql.NullString{String: ns.String, Valid: true}
	}
	return sql.NullString{}
}

// ============================================================
// 📌 DATETIME (CustomTime → sql.NullTime)
// ============================================================
func nullableDateTime(ct models.CustomTime, fallback time.Time) sql.NullTime {
	if ct.Valid && !ct.Time.IsZero() {
		return sql.NullTime{Valid: true, Time: ct.Time}
	}
	return sql.NullTime{Valid: true, Time: fallback}
}

// ============================================================
// 📌 DATETIME (NullTime → sql.NullTime)
// ============================================================
func nullableTime(nt models.NullTime, fallback time.Time) sql.NullTime {
	if nt.Valid && !nt.Time.IsZero() {
		return sql.NullTime{Valid: true, Time: nt.Time}
	}
	return sql.NullTime{Valid: true, Time: fallback}
}

// ============================================================
// 📌 DATETIME (NullString → sql.NullTime)
// ============================================================
func nullableDateTimeString(ns models.NullString, fallback time.Time) sql.NullTime {
	if !ns.Valid || strings.TrimSpace(ns.String) == "" {
		return sql.NullTime{Time: fallback, Valid: true}
	}
	t, err := parseDateTime(ns.String)
	if err != nil {
		return sql.NullTime{Time: fallback, Valid: true}
	}
	return sql.NullTime{Time: t, Valid: true}
}

// ============================================================
// 📌 STRING → sql.NullString
// ============================================================
func nullableString(val models.NullString, fallback string) sql.NullString {
	if val.Valid && strings.TrimSpace(val.String) != "" {
		return sql.NullString{String: val.String, Valid: true}
	}
	return sql.NullString{String: fallback, Valid: true}
}

// ============================================================
// 📌 GUID (UNIQUEIDENTIFIER) → interface{}
// ============================================================
func nullableUUID(v interface{}) interface{} {
	switch x := v.(type) {

	// 1️⃣ models.NullUUID → direkt geri dön
	case models.NullUUID:
		if !x.Valid {
			return nil
		}
		return x.UUID

	// 2️⃣ models.NullString → GUID parse et
	case models.NullString:
		if !x.Valid || strings.TrimSpace(x.String) == "" {
			return nil
		}
		id, err := uuid.Parse(x.String)
		if err != nil {
			return nil
		}
		return id

	// 3️⃣ string → GUID parse et
	case string:
		id, err := uuid.Parse(x)
		if err != nil {
			return nil
		}
		return id
	}

	return nil
}

// ============================================================
// 📌 NUMERIC → sql.NullX
// ============================================================
func nullableFloat64(val models.NullFloat64, fallback float64) sql.NullFloat64 {
	if val.Valid {
		return sql.NullFloat64{Float64: val.Float64, Valid: true}
	}
	return sql.NullFloat64{Float64: fallback, Valid: true}
}

func nullableInt16(val models.NullInt16, fallback int16) sql.NullInt16 {
	if val.Valid {
		return sql.NullInt16{Int16: val.Int16, Valid: true}
	}
	return sql.NullInt16{Int16: fallback, Valid: true}
}

func nullableInt32(val models.NullInt32, fallback int32) sql.NullInt32 {
	if val.Valid {
		return sql.NullInt32{Int32: val.Int32, Valid: true}
	}
	return sql.NullInt32{Int32: fallback, Valid: true}
}

func nullableInt32ToInt16(val models.NullInt32, fallback int16) sql.NullInt16 {
	if val.Valid {
		return sql.NullInt16{Int16: int16(val.Int32), Valid: true}
	}
	return sql.NullInt16{Int16: fallback, Valid: true}
}

// ============================================================
// 📌 BOOL → sql.NullBool
// ============================================================
func nullableBool(val models.NullBool, fallback bool) sql.NullBool {
	if val.Valid {
		return sql.NullBool{Bool: val.Bool, Valid: true}
	}
	return sql.NullBool{Bool: fallback, Valid: true}
}

var logger = log.Default()
