package repository

import (
	"apskel-pos-be/internal/entities"
	"context"
	"fmt"

	"github.com/google/uuid"
	"gorm.io/gorm"
)

type CustomerRepository struct {
	db *gorm.DB
}

func NewCustomerRepository(db *gorm.DB) *CustomerRepository {
	return &CustomerRepository{db: db}
}

func (r *CustomerRepository) Create(ctx context.Context, customer *entities.Customer) error {
	return r.db.WithContext(ctx).Create(customer).Error
}

func (r *CustomerRepository) GetByID(ctx context.Context, id uuid.UUID) (*entities.Customer, error) {
	var customer entities.Customer
	err := r.db.WithContext(ctx).Where("id = ?", id).First(&customer).Error
	if err != nil {
		return nil, err
	}
	return &customer, nil
}

func (r *CustomerRepository) GetByIDAndOrganization(ctx context.Context, id, organizationID uuid.UUID) (*entities.Customer, error) {
	var customer entities.Customer
	err := r.db.WithContext(ctx).Where("id = ? AND organization_id = ?", id, organizationID).First(&customer).Error
	if err != nil {
		return nil, err
	}
	return &customer, nil
}

func (r *CustomerRepository) GetDefaultCustomer(ctx context.Context, organizationID uuid.UUID) (*entities.Customer, error) {
	var customer entities.Customer
	err := r.db.WithContext(ctx).Where("organization_id = ? AND is_default = ?", organizationID, true).First(&customer).Error
	if err != nil {
		return nil, err
	}
	return &customer, nil
}

func (r *CustomerRepository) List(ctx context.Context, organizationID uuid.UUID, offset, limit int, search string, isActive, isDefault *bool, sortBy, sortOrder string) ([]entities.Customer, int64, error) {
	var customers []entities.Customer
	var total int64

	query := r.db.WithContext(ctx).Where("organization_id = ?", organizationID)

	if search != "" {
		searchTerm := "%" + search + "%"
		query = query.Where("name ILIKE ? OR email ILIKE ? OR phone ILIKE ?", searchTerm, searchTerm, searchTerm)
	}

	if isActive != nil {
		query = query.Where("is_active = ?", *isActive)
	}

	if isDefault != nil {
		query = query.Where("is_default = ?", *isDefault)
	}

	if err := query.Model(&entities.Customer{}).Count(&total).Error; err != nil {
		return nil, 0, err
	}

	if sortBy != "" {
		if sortOrder == "" {
			sortOrder = "asc"
		}
		query = query.Order(fmt.Sprintf("%s %s", sortBy, sortOrder))
	} else {
		query = query.Order("created_at DESC")
	}

	err := query.Offset(offset).Limit(limit).Find(&customers).Error
	if err != nil {
		return nil, 0, err
	}

	return customers, total, nil
}

func (r *CustomerRepository) Update(ctx context.Context, customer *entities.Customer) error {
	return r.db.WithContext(ctx).Save(customer).Error
}

func (r *CustomerRepository) Delete(ctx context.Context, id uuid.UUID) error {
	return r.db.WithContext(ctx).Delete(&entities.Customer{}, id).Error
}

func (r *CustomerRepository) SetAsDefault(ctx context.Context, customerID, organizationID uuid.UUID) error {
	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		if err := tx.Model(&entities.Customer{}).
			Where("organization_id = ? AND is_default = ?", organizationID, true).
			Update("is_default", false).Error; err != nil {
			return err
		}

		if err := tx.Model(&entities.Customer{}).
			Where("id = ? AND organization_id = ?", customerID, organizationID).
			Update("is_default", true).Error; err != nil {
			return err
		}

		return nil
	})
}

func (r *CustomerRepository) CreateDefaultCustomer(ctx context.Context, organizationID uuid.UUID) (*entities.Customer, error) {
	defaultCustomer := &entities.Customer{
		OrganizationID: organizationID,
		Name:           "Walk In Customer",
		IsDefault:      true,
		IsActive:       true,
	}

	err := r.db.WithContext(ctx).Create(defaultCustomer).Error
	if err != nil {
		return nil, err
	}

	return defaultCustomer, nil
}

func (r *CustomerRepository) GetByEmail(ctx context.Context, email string, organizationID uuid.UUID) (*entities.Customer, error) {
	var customer entities.Customer
	err := r.db.WithContext(ctx).Where("email = ? AND organization_id = ?", email, organizationID).First(&customer).Error
	if err != nil {
		return nil, err
	}
	return &customer, nil
}
