package validation

import (
	"context"
	"database/sql"
	"fmt"
	"time"
)

// ValidationConfig holds configuration for duplicate validation
type ValidationConfig struct {
	TableName        string
	IDColumn         string
	StatusColumn     string
	DateColumn       string
	ActiveStatuses   []string
	AdditionalFields map[string]interface{}
}

// DuplicateValidator provides methods for validating duplicate entries
type DuplicateValidator struct {
	db *sql.DB
}

// NewDuplicateValidator creates a new instance of DuplicateValidator
func NewDuplicateValidator(db *sql.DB) *DuplicateValidator {
	return &DuplicateValidator{db: db}
}

// ValidateDuplicate checks for duplicate entries based on the provided configuration
func (dv *DuplicateValidator) ValidateDuplicate(ctx context.Context, config ValidationConfig, identifier interface{}) error {
	query := fmt.Sprintf(`
		SELECT COUNT(*) 
		FROM %s 
		WHERE %s = $1 
		AND %s = ANY($2) 
		AND DATE(%s) = CURRENT_DATE
	`, config.TableName, config.IDColumn, config.StatusColumn, config.DateColumn)

	var count int
	err := dv.db.QueryRowContext(ctx, query, identifier, config.ActiveStatuses).Scan(&count)
	if err != nil {
		return fmt.Errorf("failed to check duplicate: %w", err)
	}

	if count > 0 {
		return fmt.Errorf("data with ID %v already exists with active status today", identifier)
	}

	return nil
}

// ValidateDuplicateWithCustomFields checks for duplicates with additional custom fields
func (dv *DuplicateValidator) ValidateDuplicateWithCustomFields(ctx context.Context, config ValidationConfig, fields map[string]interface{}) error {
	whereClause := fmt.Sprintf("%s = ANY($1) AND DATE(%s) = CURRENT_DATE", config.StatusColumn, config.DateColumn)
	args := []interface{}{config.ActiveStatuses}
	argIndex := 2

	// Add additional field conditions
	for fieldName, fieldValue := range config.AdditionalFields {
		whereClause += fmt.Sprintf(" AND %s = $%d", fieldName, argIndex)
		args = append(args, fieldValue)
		argIndex++
	}

	// Add dynamic fields
	for fieldName, fieldValue := range fields {
		whereClause += fmt.Sprintf(" AND %s = $%d", fieldName, argIndex)
		args = append(args, fieldValue)
		argIndex++
	}

	query := fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s", config.TableName, whereClause)

	var count int
	err := dv.db.QueryRowContext(ctx, query, args...).Scan(&count)
	if err != nil {
		return fmt.Errorf("failed to check duplicate with custom fields: %w", err)
	}

	if count > 0 {
		return fmt.Errorf("duplicate entry found with the specified criteria")
	}

	return nil
}

// ValidateOncePerDay ensures only one submission per day for a given identifier
func (dv *DuplicateValidator) ValidateOncePerDay(ctx context.Context, tableName, idColumn, dateColumn string, identifier interface{}) error {
	query := fmt.Sprintf(`
		SELECT COUNT(*) 
		FROM %s 
		WHERE %s = $1 
		AND DATE(%s) = CURRENT_DATE
	`, tableName, idColumn, dateColumn)

	var count int
	err := dv.db.QueryRowContext(ctx, query, identifier).Scan(&count)
	if err != nil {
		return fmt.Errorf("failed to check daily submission: %w", err)
	}

	if count > 0 {
		return fmt.Errorf("only one submission allowed per day for ID %v", identifier)
	}

	return nil
}

// GetLastSubmissionTime returns the last submission time for a given identifier
func (dv *DuplicateValidator) GetLastSubmissionTime(ctx context.Context, tableName, idColumn, dateColumn string, identifier interface{}) (*time.Time, error) {
	query := fmt.Sprintf(`
		SELECT %s 
		FROM %s 
		WHERE %s = $1 
		ORDER BY %s DESC 
		LIMIT 1
	`, dateColumn, tableName, idColumn, dateColumn)

	var lastTime time.Time
	err := dv.db.QueryRowContext(ctx, query, identifier).Scan(&lastTime)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil // No previous submission
		}
		return nil, fmt.Errorf("failed to get last submission time: %w", err)
	}

	return &lastTime, nil
}

// DefaultRetribusiConfig returns default configuration for retribusi validation
func DefaultRetribusiConfig() ValidationConfig {
	return ValidationConfig{
		TableName:      "data_retribusi",
		IDColumn:       "id",
		StatusColumn:   "status",
		DateColumn:     "date_created",
		ActiveStatuses: []string{"active", "draft"},
	}
}
