package filters

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"gorm.io/gorm"
)

type FilterFunction = func(*gorm.DB) *gorm.DB

func Where(statement string, args ...interface{}) Filter {
	filt := func(db *gorm.DB) *gorm.DB {
		return db.Where(statement, args...)
	}
	return Filter{
		category: WHERE_FILTER,
		filter:   filt,
	}
}

func StructToWhereScope[T any](model T) Filter {
	filt := func(db *gorm.DB) *gorm.DB {
		return db.Where(model)
	}
	return Filter{
		category: WHERE_FILTER,
		filter:   filt,
	}
}

func Order(field string, desc bool) Filter {
	var filt FilterFunction
	if desc {
		filt = func(d *gorm.DB) *gorm.DB {
			return d.Order(field + " DESC")
		}
	} else {
		filt = func(d *gorm.DB) *gorm.DB {
			return d.Order(field)
		}
	}
	return Filter{
		category: ORDER_FILTER,
		filter:   filt,
	}
}

func WhereFromStrings(column, conditionOperator, value string) Filter {
	var filt func(*gorm.DB) *gorm.DB

	if strings.HasPrefix(value, "~") {
		value = strings.ReplaceAll(value, "~", "")

		filt = func(d *gorm.DB) *gorm.DB {
			// return d.Where("lower("+column+`) LIKE lower(?)`, "%"+value+"%")
			// (jeśli masz collation case-insensitive, np. utf8mb4_general_ci)
			return d.Where(column+` LIKE ?`, "%"+value+"%")

		}

		return Filter{
			category: LIKE_FILTER,
			filter:   filt,
		}
	}

	// Handle IN operator for comma-separated values (e.g., product_id_in=1,2,3,4)
	if conditionOperator == "IN" {
		parts := strings.Split(value, ",")
		var values []interface{}
		for _, p := range parts {
			p = strings.TrimSpace(p)
			if p == "" {
				continue
			}
			// Try to parse as int first
			if i, err := strconv.ParseInt(p, 10, 64); err == nil {
				values = append(values, i)
			} else if f, err := strconv.ParseFloat(p, 64); err == nil {
				values = append(values, f)
			} else {
				values = append(values, p)
			}
		}
		filt = func(d *gorm.DB) *gorm.DB {
			return d.Where(column+" IN ?", values)
		}
		return Filter{
			category: WHERE_FILTER,
			filter:   filt,
		}
	}

	if strings.Contains(value, "]") && strings.Contains(value, "[") {
		period := strings.ReplaceAll(value, "[", "")
		period = strings.ReplaceAll(period, "]", "")
		vals := strings.Split(period, ",")
		if len(vals) == 2 {
			from, errA := time.Parse("2006-01-02", vals[0])
			to, errB := time.Parse("2006-01-02", vals[1])
			if errA == nil && errB == nil {
				filt = func(d *gorm.DB) *gorm.DB {
					return d.Where(column+` BETWEEN ? AND ?`, from.Format("2006-01-02"), to.Format("2006-01-02"))
				}

				return Filter{
					category: WHERE_FILTER,
					filter:   filt,
				}
			} else {
				filt = func(d *gorm.DB) *gorm.DB {
					return d.Where(column+` BETWEEN ? AND ?`, vals[0], vals[1])
				}

				return Filter{
					category: WHERE_FILTER,
					filter:   filt,
				}
			}

		}
	}

	if conditionOperator == "LIKE" {
		value = fmt.Sprintf("%%%s%%", value)
	}

	// in future add more grouping functions
	if strings.Contains(strings.ToLower(column), "count(") {
		filt = func(d *gorm.DB) *gorm.DB {
			return d.Having(column+` `+conditionOperator+` ?`, value)
		}

		return Filter{
			category: WHERE_FILTER,
			filter:   filt,
		}
	}

	if i, err := strconv.ParseInt(value, 10, 64); err == nil {
		filt = func(d *gorm.DB) *gorm.DB {
			return d.Where(column+` `+conditionOperator+` ?`, i)
		}
		return Filter{
			category: WHERE_FILTER,
			filter:   filt,
		}
	}
	if f, err := strconv.ParseFloat(value, 64); err == nil {
		filt = func(d *gorm.DB) *gorm.DB {
			return d.Where(column+` `+conditionOperator+` ?`, f)
		}
		return Filter{
			category: WHERE_FILTER,
			filter:   filt,
		}
	}
	if b, err := strconv.ParseBool(value); err == nil {
		filt = func(d *gorm.DB) *gorm.DB {
			return d.Where(column+` `+conditionOperator+` ?`, b)
		}
		return Filter{
			category: WHERE_FILTER,
			filter:   filt,
		}
	}

	filt = func(d *gorm.DB) *gorm.DB {
		return d.Where(column+` `+conditionOperator+` ?`, value)
	}

	return Filter{
		category: WHERE_FILTER,
		filter:   filt,
	}
}
